LeetCode 词典中最长的单词(前缀树)

版权声明:本文为博主原创文章,博客地址:https://blog.csdn.net/qq_41855420,未经博主允许不得转载。 https://blog.csdn.net/qq_41855420/article/details/89604744

给出一个字符串数组words组成的一本英语词典。从中找出最长的一个单词,该单词是由words词典中其他单词逐步添加一个字母组成。若其中有多个可行的答案,则返回答案中字典序最小的单词。

若无答案,则返回空字符串。

示例 1:

输入: 
words = ["w","wo","wor","worl", "world"]
输出: "world"
解释: 
单词"world"可由"w", "wo", "wor", 和 "worl"添加一个字母组成。

示例 2:

输入: 
words = ["a", "banana", "app", "appl", "ap", "apply", "apple"]
输出: "apple"
解释: 
"apply"和"apple"都能由词典中的单词组成。但是"apple"得字典序小于"apply"。

注意:

所有输入的字符串都只包含小写字母。
words数组长度范围为[1,1000]。
words[i]的长度范围为[1,30]。

思路分析: 我们首先按照字典升序排序words,并且新建set用于存放由words词典中其他单词逐步添加一个字母组成的单词。
然后从前往后扫描words,如果word是合法字符串(该单词是由words词典中其他单词逐步添加一个字母组成),则它的长度 == 1,或者word的前wordSize - 1组成的单词是由words词典中其他单词逐步添加一个字母组成的单词。

class Solution {
public:
	string longestWord(vector<string>& words) {
		string res = "";
		set<string> mySet;//用于存放由words词典中其他单词逐步添加一个字母组成的单词
		sort(words.begin(), words.end());//按照字典升序排序
		for (auto &word : words) {
			int wordSize = word.size();
			if (wordSize == 1 || mySet.find(word.substr(0, word.size() - 1)) != mySet.end()) {
                //当word的长度为1,或者word的前wordSize - 1组成的单词是由words词典中其他单词逐步添加一个字母组成的单词,这时word也是合法的
                mySet.insert(word);
				if (wordSize > res.size()) {//更新最大长度的单词,由于words已经按照字典升序排序,所以只要考虑长度
					res = word;
				}
			}
		}
		return res;
	}
};

在这里插入图片描述
方法二:这种单词的搜索,一般都会使用前缀树(字典树)的数据结构进行辅助。关于前缀树请翻阅 LeetCode 实现Trie(前缀树)

//前缀树的程序表示
class TrieNode {
public:
	bool isWord;//当前节点为结尾是否是单词
	vector<TrieNode*> children;
	TrieNode() : isWord(false), children(26, nullptr) {}
	~TrieNode() {
		for (TrieNode* child : children)
			if (child) delete child;
	}
};

class Solution {
public:
	string resStr = "";//存储结果
	TrieNode *trieRoot;//构建的单词后缀树
	string longestWord(vector<string>& words) {
		trieRoot = new TrieNode();
		for (auto &word : words) {
			addWord(word);
		}
		string tempStr = "";
		myFind(trieRoot, tempStr);
		return resStr;
	}
	//在树中插入一个单词的方法实现
	void addWord(string &word) {
		TrieNode *ptr = trieRoot;//扫描这棵树,将word插入
		//将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;//标记为单词
	}
	//扫描root,寻找最长的合法单词
	void myFind(TrieNode *root, string &resWord) {
		if (root != NULL) {
			//搜索它的二十六个指针
			for (int index = 0; index < 26; ++index) {
                //只有当这个子指针指向的字母是一个单词的尾端,以这个字母结尾的单词才能是一个合法的结果
				if (root->children[index] != NULL && root->children[index]->isWord) {
					string newStr = resWord + char('a' + index);
					if (newStr.size() > resStr.size()) {
						resStr = newStr;
					}
					myFind(root->children[index], newStr);
				}
			}
		}
	}
};

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41855420/article/details/89604744