1. 程式人生 > >Map Sum Pairs 鍵值對映

Map Sum Pairs 鍵值對映

實現一個 MapSum 類裡的兩個方法,insert 和 sum

對於方法 insert,你將得到一對(字串,整數)的鍵值對。字串表示鍵,整數表示值。如果鍵已經存在,那麼原來的鍵值對將被替代成新的鍵值對。

對於方法 sum,你將得到一個表示字首的字串,你需要返回所有以該字首開頭的鍵的值的總和。

示例 1:

輸入: insert("apple", 3), 輸出: Null
輸入: sum("ap"), 輸出: 3
輸入: insert("app", 2), 輸出: Null
輸入: sum("ap"), 輸出: 5

思路一:構建一個詞典字首樹,構建的方法參見Implement Trie (Prefix Tree) 實現 Trie (字首樹)

,那麼我們只需要修改startsWith方法即可,原題中只需要返回是否存在prefix的字串,而這道題要求返回以prefix字首的string的對應int的累加和。所以我們在遍歷到字串為prefix的字首樹時需要一個變數res來記錄累加的和,這裡注意字首字串prefix必須全部滿足才算找到一個,比如prefix為“abc”,那麼當匹配到“ab”時,即使是一個單詞,也不能算在內。並且當匹配完“abc”後,我們需要BFS或者DFS來遍歷剩下的每一種情況,由於字首樹是類似決策樹的分支結構,所以不存在重複性掃描的問題,所以不需要記憶陣列visited來儲存已經訪問過的節點。

參考程式碼如下:

class MapSum {
	struct Trie {
		bool isWord;
		Trie* children[26] = {};
		Trie() :isWord(false) {
			for (auto &child : children) child = nullptr;
		}
	};
	class TrieNode {
	public:
		TrieNode() {
			root = new Trie();
		}
		void insert(string &word) {
			Trie *p = root;
			for (auto &ch : word) {
				if (!p->children[ch - 'a']) p->children[ch - 'a'] = new Trie();
				p = p->children[ch - 'a'];
			}
			p->isWord = true;
		}
		void packageInsert(string word, int val) {
			insert(word);
			m[word] = val;
		}
		void dfs(Trie* p,int &sum, string tmp) {
			if (p->isWord) {
				sum += m[tmp];
			}
			for (int i = 0; i < 26; i++) {
				char ch = ('a' + i);
				if (p->children[i]) dfs(p->children[i], sum, tmp + ch);
			}
		}
		int searchPrefix(string &pre) {
			int res=0;
			Trie *p = root;
			string tmp;
			for (auto &ch : pre) {
				if (!p->children[ch - 'a']) return res;
				p = p->children[ch - 'a'];
			}
			tmp = pre;
			dfs(p, res, tmp);
			return res;
		}

	private:
		Trie * root;
		unordered_map<string, int> m;
	};
public:
	/** Initialize your data structure here. */
	MapSum() {
		node = new TrieNode();
	}

	void insert(string key, int val) {
		node->packageInsert(key, val);
	}

	int sum(string prefix) {
		return node->searchPrefix(prefix);
	}
private:
	TrieNode * node;
};

思路二:需要兩個hashmap,m和score,其中m儲存每一個輸入的<string,int>的對應關係,而score直接儲存對應prefix的分數,具體做法為每當有insert操作時,我們計算一個delta值=val-m[string],然後對string的每一個char都更新這個score,即如下核心程式碼:

	void insert(string key, int val) {
		int delta = val - m[key];
		m[key] = val;
		string prefix = "";
		for (auto &ch : key) {
			prefix += ch;
			score[prefix] = ((score.find(prefix)==score.end())?0:score[prefix] + delta);
		}
	}

相當於我們儲存每一個string的所有第一個字元開始的子序列的分數,並且這個操作的巧妙之處在於可以完成:覆蓋和替換的功能,那麼當呼叫sum函式時,我們直接返回score[prefix]即可。

參考程式碼如下:

class MapSum {
public:
	/** Initialize your data structure here. */
	MapSum() {
	}

	void insert(string key, int val) {
		int delta = val - m[key];
		m[key] = val;
		string prefix = "";
		for (auto &ch : key) {
			prefix += ch;
			score[prefix] = ((score.find(prefix)==score.end())?0:score[prefix] + delta);
		}
	}

	int sum(string prefix) {
		return score[prefix];
	}
private:
	unordered_map<string, int> m;
	unordered_map<string, int> score;
};

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