1. 程式人生 > >677. Map Sum Pairs(python+cpp)(包含字首樹解法)

677. Map Sum Pairs(python+cpp)(包含字首樹解法)

題目:

Implement a MapSum class with insert, and sum methods.
For the method insert, you’ll be given a pair of (string, integer).The string represents the key and the integer represents the value. If the key already existed, then the original key-value pair will be overridden to the new one.
For the method sum

, you’ll be given a string representing the prefix,and you need to return the sum of all the pairs’ value whose key starts with the prefix.
Example 1:

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

解釋:


這題可以用字典做,但是更經典的解法是Trie
字典解法,
1.在插入時直接插入,在求和是查詢所有字首,插入快
2.也可以在插入的時候記入所有字首,查詢快。
3.字首樹解法
第一種解法在c++中,可以利用map對key排序的特點,map.lower_bound(prefix)就可以得到可能以prefix為字首的最小鍵值對,然後從這裡開始遍歷,滿足條件便將其累加,不滿足條件則可以終止遍歷。最後return累加值。
解法一:
python程式碼:

class MapSum(object):
    def __init__(self):
        """
        Initialize your data structure here.
        """
self._dict={} def insert(self, key, val): """ :type key: str :type val: int :rtype: void """ self._dict[key]=val def sum(self, prefix): """ :type prefix: str :rtype: int """ result=0 for key in self._dict.keys(): if key.find(prefix)==0: result+=self._dict[key] return result # Your MapSum object will be instantiated and called as such: # obj = MapSum() # obj.insert(key,val) # param_2 = obj.sum(prefix)

c++程式碼:

#include <map>
using namespace std;
class MapSum {
public:
    /** Initialize your data structure here. */
    map<string,int>_map;
    MapSum() { 
    }
    void insert(string key, int val) {
        _map[key]=val;
    }
    int sum(string prefix) {
        int _sum=0;
        for (auto it = _map.lower_bound(prefix); it != _map.end();it++){
            if (it->first.find(prefix)==0)
                _sum += it->second;
        }
        return _sum;
    }
};
/**
 * Your MapSum object will be instantiated and called as such:
 * MapSum obj = new MapSum();
 * obj.insert(key,val);
 * int param_2 = obj.sum(prefix);
 */

判斷key是否以prefix開頭也可以用以下程式碼:

int sum = 0, len = prefix.size();
for (auto it = m.lower_bound(prefix); it != m.end();++it){
    if (it->first.substr(0,len) == prefix) 
    	sum += it->second;
}
return sum;

一個是查詢字串開始的位置,一個是從同一開始取指定長度的子字串看是否相等。
解法2:
python程式碼:

class MapSum(object):

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self._dict={}
        self._sum={}
    def insert(self, key, val):
        """
        :type key: str
        :type val: int
        :rtype: void
        """
        diff=val-self._dict.get(key,0)
        for i in range(0,len(key)):
            sub=key[:i+1]
            self._sum[sub]=self._sum.get(sub,0)+diff
        self._dict[key] =val
    def sum(self, prefix):
        """
        :type prefix: str
        :rtype: int
        """
        return self._sum.get(prefix,0)
# Your MapSum object will be instantiated and called as such:
# obj = MapSum()
# obj.insert(key,val)
# param_2 = obj.sum(prefix)

c++程式碼(速度沒有解法1快):

#include <map>
using namespace std;
class MapSum {
public:
    /** Initialize your data structure here. */
    map<string ,int>_map;
    map<string ,int>_sum;
    MapSum() {
    }
    void insert(string key, int val) {
        int diff=val-_map[key];
        for (int i=0;i<key.size();i++)
        {
            string sub=key.substr(0,i+1);
            _sum[sub]+=diff;
        }
        _map[key]=val;
    }
    int sum(string prefix) {
        return _sum[prefix];
    }
};
/**
 * Your MapSum object will be instantiated and called as such:
 * MapSum obj = new MapSum();
 * obj.insert(key,val);
 * int param_2 = obj.sum(prefix);
 */

字首樹解法:

#感覺這道題是經典的字典樹問題
from collections import defaultdict
class TrieNode(object):
    def __init__(self):
        self.children=defaultdict(TrieNode)
        self.isWord=False
        self.freq=0
        
class MapSum(object):

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.root=TrieNode()
        self._dict={}
        
    def insert(self, key, val):
        """
        :type key: str
        :type val: int
        :rtype: void
        """
        current=self.root
        for letter in key:
            current=current.children[letter]
            current.freq+=val-self._dict.get(key,0)
        current.isWord=True
        self._dict[key]=val
        
    def sum(self, prefix):
        """
        :type prefix: str
        :rtype: int
        """
        current =self.root
        for letter in prefix:
            current=current.children.get(letter)
            if current==None:
                return 0
        return current.freq

# Your MapSum object will be instantiated and called as such:
# obj = MapSum()
# obj.insert(key,val)
# param_2 = obj.sum(prefix)

c++程式碼:

#include <map>
using namespace std;
struct TrieNode{
    bool isWord;
    map<char,TrieNode*>children;
    int freq;
    TrieNode():isWord(false),freq(0) {};
};
class MapSum {
public:
    /** Initialize your data structure here. */
    TrieNode *root;
    map<string,int>visited;
    MapSum() {
        root=new TrieNode();
    }
    
    void insert(string key, int val) {
        TrieNode* current=root;
        for(auto letter:key)
        {
            if (!current->children.count(letter))
                current->children[letter]=new TrieNode();
            current=current->children[letter];
            current->freq+=val-visited[key];
        }
        current->isWord=true;
        visited[key]=val;
    }
    
    int sum(string prefix) {
        TrieNode* current=root;
        for(auto letter:prefix)
        {
            if (!current->children.count(letter))
                return 0;
            current=current->children[letter];
            
        }
        return current->freq;
    }
};

/**
 * Your MapSum object will be instantiated and called as such:
 * MapSum obj = new MapSum();
 * obj.insert(key,val);
 * int param_2 = obj.sum(prefix);
 */

總結: