LeetCode 前缀和后缀搜索(前缀树)

描述:

给定多个 words,words[i] 的权重为 i 。

设计一个类 WordFilter 实现函数WordFilter.f(String prefix, String suffix)。这个函数将返回具有前缀 prefix 和后缀suffix 的词的最大权重。如果没有这样的词,返回 -1。

示例:

输入:
WordFilter(["apple"])
WordFilter.f("a", "e") // 返回 0
WordFilter.f("b", "") // 返回 -1

注意:

words的长度在[1, 15000]之间。
对于每个测试用例,最多会有words.length次对WordFilter.f的调用。
words[i]的长度在[1, 10]之间。
prefix, suffix的长度在[0, 10]之前。
words[i]和prefix, suffix只包含小写字母。

思路分析:

这种单词的搜索,一般都是使用前缀树来处理,即通过前缀树的结构来来储存所有的单词集合,在搜索单词时减少重复搜索的目的。关于前缀树及其运用请翻阅 前缀树实现以及运用

第一步:建树。将vector& words转换为前缀树
第二步:首先判断前缀prefix是否存在
第三步:在以prefixRoot为起始的子树中,搜索单词的后缀为suffix的最大权值
//前缀树的程序表示
class TrieNode {
public:
	bool isWord;//当前节点为结尾是否是单词
	int weight = 0;//只用当isWord == true,权重才有意义
	vector<TrieNode*> children;
	TrieNode() : isWord(false), children(26, nullptr), weight(0) {}
	~TrieNode() {
		for (TrieNode* child : children)
			if (child) delete child;
	}
};

class WordFilter {
public:
	TrieNode *trieRoot;//构建的单词前缀树
    //往树中添加一个单词以及对应的权重
	void addWord(string &word, int weight) {
		TrieNode *ptr = trieRoot;//扫描这棵树,插入word
		for (auto ch : word) {
			if (ptr->children[ch - 'a'] == NULL) {
				ptr->children[ch - 'a'] = new TrieNode();
			}
			ptr = ptr->children[ch - 'a'];
		}
		ptr->isWord = true;//标记为单词
		ptr->weight = weight;//记录权重
	}
	//在单词的前缀树中搜索前缀prefix是否存在,并且返回前缀对应的节点
	TrieNode *myFindPrefix(string &prefix){
		TrieNode *ptr = trieRoot;//扫描这棵树
		for (auto ch : prefix){
			if (ptr->children[ch - 'a'] == NULL) {
                //如果前缀prefix不存在,则返回空值
				return NULL;
			}
			else{
				ptr = ptr->children[ch - 'a'];
			}
		}
		return ptr;//否则返回前缀prefix结尾的节点地址
	}
    //在以prefixRoot为起始的子树中,搜索单词的后缀为suffix的最大权值
    void myFind(TrieNode *prefixRoot, string word, string &suffix, int &maxRes){
		if (prefixRoot->isWord && word.substr(word.size() - suffix.size()) == suffix){
            //如果prefixRoot此时是一个单词的结尾,并且这个单词的后缀是suffix
			maxRes = max(maxRes, prefixRoot->weight);
		}
		int wordSize = word.size();
		word += 'a';
        //尝试搜索prefixRoot的26个非空子节点
		for (int index = 0; index < 26; ++index){
			if (prefixRoot->children[index]){//非空
				word[wordSize] = 'a' + index;
				myFind(prefixRoot->children[index], word, suffix, maxRes);
			}
		}
	}
	WordFilter(vector<string>& words) {
        //vector& words转换为前缀树
		trieRoot = new TrieNode();
		int wordsSize = words.size();
		for (int index = 0; index < wordsSize; ++index){
			addWord(words[index], index);
		}
	}
	
	int f(string prefix, string suffix) {
        //第一步判断前缀prefix是否存在
		TrieNode *prefixRoot = myFindPrefix(prefix);
		if (prefixRoot == NULL){
			return -1;
		}
        //在以prefixRoot为起始的子树中,搜索单词的后缀为suffix的最大权值
		int maxRes = -1;
		myFind(prefixRoot, prefix, suffix, maxRes);
		return maxRes;
	}
};

/**
 * Your WordFilter object will be instantiated and called as such:
 * WordFilter* obj = new WordFilter(words);
 * int param_1 = obj->f(prefix,suffix);
 */

LeetCode 前缀和后缀搜索(前缀树)_第1张图片

你可能感兴趣的:(LeetCode,树,前缀树,字符串)