力扣-139-单词拆分

前缀树模板题?

直接看题解,明明是前缀树标签,却只给了动态规划

前缀树

我试图用208前缀树的直接思路解决这个问题

class Trie {
private:
	vector<Trie*> children;
	bool isEnd;

public:
	Trie() :children(26), isEnd(false) {}

	void insert(string word) {
		Trie* node = this;
		for (char ch : word) {
			ch -= 'a';
			if (node->children[ch] == nullptr)
				node->children[ch] = new Trie();
			node = node->children[ch];
		}
		node->isEnd = true;
	}

	bool wordBreak(string input) {
		Trie* node = this;
		for (int i = 0; i < input.length(); i++) {
			input[i] -= 'a';
			if (node->children[input[i]] == nullptr) return false;
			node = node->children[input[i]];
			if (node->isEnd && i != input.length() - 1)node = this;
		}
		return node->isEnd;
	}
};

class Solution {
public:
	bool wordBreak(string s, vector<string>& wordDict) {
		Trie trie;
		for (string str : wordDict) trie.insert(str);
		return trie.wordBreak(s);
	}
};

但是卡在了这两个测试用例

"aaaaaaa"
["aaaa","aa"]

"aaaaaaa"
["aaaa","aaa"]

还是逃不掉动态规划吗

我又改成这样

	bool wordBreak(string input,int start) {
		Trie* node = this;
		for (int i = start; i < input.length(); i++) {
			input[i] -= 'a';
			if (node->children[input[i]] == nullptr) return false;
			node = node->children[input[i]];
			if (node->isEnd && i != input.length() - 1) 
				if (wordBreak(input, i + 1))return true;
		}
		return node->isEnd;
	}

然后被预判了,果断超时

动态规划

思路是判断i个位置,以strArr[i]结尾的字符串是否可以由状态转移方程递归出来
而每一次判断都需要从头遍历j位置,看以j做分隔的字符串能否由字典中的字符串构成

class Trie {
private:
	vector<Trie*> children;
	bool isEnd;
public:
	Trie() :children(26), isEnd(false) {}

	void insert(string word) {
		Trie* node = this;
		for (char ch : word) {
			ch -= 'a';
			if (node->children[ch] == nullptr)
				node->children[ch] = new Trie();
			node = node->children[ch];
		}
		node->isEnd = true;
	}

	bool search(string word) {
		Trie* node = this;
		for (char ch : word) {
			ch -= 'a';
			if (node->children[ch] == nullptr)
				return false;
			node = node->children[ch];
		}
		return node->isEnd;
	}
};

class Solution {
public:
	bool wordBreak(string s, vector<string>& wordDict) {
		Trie trie;
		for (string str : wordDict) trie.insert(str);
		int len = s.length();
		vector<bool> dp(len + 1);
		dp[0] = 1;
		for (int i = 1; i <= s.length(); i++) {
			for (int j = 0; j < i; j++) {
				if (dp[j] && trie.search(s.substr(j, i - j))) {
					dp[i] = true;
					break;
				}
			}
		}
		return dp[len];
	}
};

自己写不如用现成的系列,本质还是动态规划,只是前缀树代替了set而已

class Solution {
public:
	bool wordBreak(string s, vector<string>& wordDict) {
		Trie trie;
		int maxLen = wordDict[0].length();
		for (string str : wordDict) {
			trie.insert(str);
			if (str.size() > maxLen) maxLen = str.size();
		}
		int len = s.length();
		vector<bool> dp(len + 1);
		dp[0] = 1;
		for (int i = 1; i <= s.length(); i++) {
			for (int j = 0; j < i; j++) {
				// 剪枝:如果i-j的字符串长度已经大于了字典中最长字符串的长度
				if (i - j > maxLen) continue;
				if (dp[j] && trie.search(s.substr(j, i - j))) {
					dp[i] = true;
					break;
				}
			}
		}
		return dp[len];
	}
};

加上剪枝,情况好了很多

posted @ 2022-11-18 17:02  YaosGHC  阅读(30)  评论(0)    收藏  举报