leetcode设计类题目——677. 键值映射

题目


OJ平台

需求分析

需求:

  1. 插入单词与值形成联系
  2. 查询前缀对应的所有单词的值的和
  • 很明显,直接用字典树便可完成这个需求。

但有一个问题:如何快速得到这个前缀对应的所有单词的和?

很简单的处理方式就是利用哈希表对每个单词的权值进行记录 ,如果出现替换键值映射的情况,那就将这次的加和值减去原来的值。

当然也可不用哈希表,直接多设置一个 f 标记用于区分单词结尾,顺便记录这个单词对应的权值,如果出现键值替换的情况,直接就将这个值从头再减去一遍即可。

代码部分

解题代码:

struct str{
    
    //用于标记是否存在这个单词,且保存它对应的权值
    int v;
    str(int v):v(v){
    
    }
};

struct node{
    
    //字典树的结点
    str* f;
    int w;
    node* next[26];
    node(int w):w(w),f(nullptr){
    
    
        memset(next,0,sizeof(node*)*26);
    }
};

class MapSum {
    
    
public:
    node* head;
    MapSum() {
    
    
        head = new node(0);
    }

    void insert(string key, int val) {
    
    
        //思路很简单,就是插入的时候把经过的路径上加上之前的带权值
        int pos;
        node* root = head;
        for(auto&& ch:key){
    
    
                pos = ch-'a';
            if(root->next[pos] == 0){
    
    
                root->next[pos] = new node(val);
            }else{
    
    
                root->next[pos]->w += val;
            }
            root = root->next[pos];
        }

        if(root->f){
    
    //如果这个键值已经存在,则往回减去这个 v 值
            int _val = root->f->v;
            node* _root = head;
            for(auto&&ch : key){
    
    
                pos = ch-'a';
                _root->next[pos]->w -= _val;
                _root = _root->next[pos];
            }
            _root->f->v = val;
        }else{
    
    
            root->f = new str(val);
        }
    }
    int sum(string prefix) {
    
    
        node* root = head;
        for(auto&& ch: prefix){
    
    //由于w直接就记录了整个带权路径和,所以只要找到prefix的终点即可
            if(root->next[ch-'a']!=0)
                root = root->next[ch-'a'];
            else
                return 0;
        }
        return root->w;
    }
};

工业化代码:

struct str{
    
    //用于标记是否存在这个单词,且保存它对应的权值
    int v;
    str(int v):v(v){
    
    }
};

struct node{
    
    //字典树的结点
    str* f;
    int w;
    node* next[26];
    node(int w):w(w),f(nullptr){
    
    
        memset(next,0,sizeof(node*)*26);
    }
};

class MapSum {
    
    
private:
    void destroy(node* root){
    
    
        if(!root)
            return;
        for(int i=0;i<26;i++){
    
    
            if(root->next[i]){
    
    
                destroy(root->next[i]);
            }
        }
        if(root->f)
            delete root->f;
        delete root;
    }
public:
    node* head;
    MapSum() {
    
    
        head = new node(0);
    }
    ~MapSum() {
    
    
        destroy(head);
    }
    
    void insert(string key, int val) {
    
    
        //思路很简单,就是插入的时候把经过的路径上加上之前的带权值
        int pos;
        node* root = head;
        for(auto&& ch:key){
    
    
                pos = ch-'a';

            assert(root != 0); //老师说工业界代码要加几个断言

            if(root->next[pos] == 0){
    
    
                root->next[pos] = new node(val);
            }else{
    
    
                root->next[pos]->w += val;
            }
            root = root->next[pos];
        }

        if(root->f){
    
    //如果这个键值已经存在,则往回减去这个 v 值
            int _val = root->f->v;
            node* _root = head;
            for(auto&&ch : key){
    
    
                pos = ch-'a';
                _root->next[pos]->w -= _val;
                _root = _root->next[pos];
            }
            _root->f->v = val;
        }else{
    
    
            root->f = new str(val);
        }
    }
    int sum(string prefix) {
    
    
        node* root = head;
        for(auto&& ch: prefix){
    
    //由于w直接就记录了整个带权路径和,所以只要找到prefix的终点即可
            assert(root != 0);
            if(root->next[ch-'a']!=0)
                root = root->next[ch-'a'];
            else
                return 0;
        }
        return root->w;
    }
};

猜你喜欢

转载自blog.csdn.net/m0_50945504/article/details/121318268