最开始的思路是所有字符串匹配,但有逻辑错误,因为可能字典里的单词有相同的前缀和后缀。
错误代码,能通过部分样例
class Solution {
public:
int respace(vector<string>& dictionary, string sentence) {
int falg = false;
int ci = 0;
vector <string> dict[26];
for(int i = 0; i < dictionary.size(); i++) {
dict[dictionary[i][0]-'a'].push_back(dictionary[i]);
}
for(int i = 0 ; i < sentence.size(); i++){
int ch = sentence[i] - 'a';
falg = false;
for(int j = 0; j < dict[ch].size();j++){
if(i+dict[ch][j].size() <= sentence.size() && sentence.substr(i,dict[ch][j].size()) == dict[ch][j]){
i += dict[ch][j].size();
falg = true;
break;
}
}
if(falg) i--;
else ci++;
}
return ci;
}
};
看了官方的题解,了解了一种新的数据结构---------字典树,单词树,字符串树
字典树的三个特性:
根节点不包含字符,除根节点外每一个节点都只包含一个字符
从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串
每个节点的所有子节点包含的字符都不相同
该题目用的字典树是逆序字典树
just like looked brother
状态转移方程:
每次isEnd 为真时改变一次转态,但要继续搜索下去(考虑相同后缀)
class Trie {
public:
Trie* next[26] = {nullptr};
bool isEnd;
Trie() {
isEnd = false;
}
void insert(string s) {
Trie* curPos = this;
for (int i = s.length() - 1; i >= 0; --i) {
int t = s[i] - 'a';
if (curPos->next[t] == nullptr) {
curPos->next[t] = new Trie();
}
curPos = curPos->next[t];
}
curPos->isEnd = true;
}
};
class Solution {
public:
int respace(vector<string>& dictionary, string sentence) {
int n = sentence.length(), inf = 0x3f3f3f3f;
Trie* root = new Trie();
for (auto& word: dictionary) {
root->insert(word);
}
vector<int> dp(n + 1, inf);
dp[0] = 0;
for (int i = 1; i <= n; ++i) {
dp[i] = dp[i - 1] + 1;
Trie* curPos = root;
for (int j = i; j >= 1; --j) {
int t = sentence[j - 1] - 'a';
if (curPos->next[t] == nullptr) {
break;
} else if (curPos->next[t]->isEnd) {
dp[i] = min(dp[i], dp[j - 1]);
}
if (dp[i] == 0) {
break;
}
curPos = curPos->next[t];
}
}
return dp[n];
}
};