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);
 */

猜你喜欢

转载自blog.csdn.net/qq_26410101/article/details/82950281
今日推荐