问题入口

实现

通过递归很好解决该问题,但是由于遍历次数过多引发了Runtime Error(ps:这是用C语言编写的情况下),所以需要寻找其他解决方法。

在我原本使用递归思路解决问题时,我对MapSum结构体定义如下:

struct MapSum{
 MapSum **next;
    int value;
};

value>0(题目给的值都是正数)就表达了这个单词的值 ,同时也说明这是单词的结尾。等于一个属性参与了两个动作。

如果我把每次加入的值都加在每一个字母上又会如何呢?

例如,进行如下操作

Input: insert("apple", 3), Output: Null
Input: sum("ap"), Output: 3
Input: insert("app", 2), Output: Null
Input: sum("ap"), Output: 5

 【Leetcode&C&Tire】677. Map Sum Pairs

可以看到第二次加入的app,对应的三个字母的值都是5。这样sum操作就仅是通过for循环到达第二个p的位置 ,返回value即可。

然而如果是更新操作,值会叠加,不会更新。

Input: insert("apple", 3), Output: Null
Input: sum("ap"), Output: 3
Input: insert("apple", 2), Output: Null
Input: sum("ap"), Output: 5 // incorrect, the answer is 2 

对于更新操作,我们需要再遍历一次Tire树减去之前的value ——即添加后的value-形参value。另外,结构体MapSum需要添加一个属性bool isWord。因为此时的value是用来表现包含这个字母的值的总和,它不具备判断是否是一个单词的语义。而isWord可以判断是进行添加操作还是更新操作。如果isWord为true,证明这是更新操作,我们需要减去之前的value;如果isWord为false, 证明这是增加操作。

#define LEN 26

typedef struct MapSum MapSum;
struct MapSum{
 MapSum **next;
    int value;
    bool isWord;
};

/** Initialize your data structure here. */

MapSum* mapSumCreate() {
    MapSum *ms = malloc(sizeof(MapSum));
    int space = sizeof(MapSum*)*LEN;
    ms->next = malloc(space);
    memset(ms->next,0,space);
    ms->value = 0;
    ms->isWord=false;
    return ms;
}

void updateValue(MapSum* obj, char *key,int val){
    for(int i=0;key[i]!='\0';i++){
        int nIndex=key[i]-'a';
        obj=obj->next[nIndex];
        obj->value+=val;
    }
}

void mapSumInsert(MapSum* obj, char * key, int val) {
    MapSum *root = obj;
  for(int i=0;key[i]!='\0';i++){
      int nIndex = key[i]-'a';
      if(!(obj->next[nIndex]))
        obj->next[nIndex]=mapSumCreate();
      obj=obj->next[nIndex];
      obj->value+=val;
  }  
  if(obj->isWord)
      updateValue(root,key,-1*(obj->value-val));
  obj->isWord=true;
}


int mapSumSum(MapSum* obj, char * prefix) {
  for(int i=0;prefix[i]!='\0';i++){
      int nIndex = prefix[i]-'a';
      if(obj->next[nIndex])
        obj=obj->next[prefix[i]-'a'];
      else
          return NULL;
  }
  return obj->value;
}

void mapSumFree(MapSum* obj) {
    free(obj->next);
    free(obj);
}

/**
 * Your MapSum struct will be instantiated and called as such:
 * MapSum* obj = mapSumCreate();
 * mapSumInsert(obj, key, val);
 
 * int param_2 = mapSumSum(obj, prefix);
 
 * mapSumFree(obj);
*/

最后来分析一下时间复杂度。假设添加的单词有n个字符,查找的前缀有k个字符。那么增加操作的时间复杂度为O(n),查找操作的时间复杂度为O(k) 

相关文章: