LC.面试题 17.13. 恢复空格

思路: T r i e + D P Trie+DP Trie+DP。

考虑令前 i i i个字符的最小未被识别字符数为 d p [ i ] dp[i] dp[i],

我们先以 d p [ i − 1 ] dp[i-1] dp[i−1]转移一次 d p [ i ] = d p [ i − 1 ] + 1 dp[i]=dp[i-1]+1 dp[i]=dp[i−1]+1。即假设 s [ i ] s[i] s[i]没有对应的字典。

然后我们需要在 [ 0 , i ] [0,i] [0,i]找到最小的 j ∈ [ 0 , i ] → s [ j … i ] j\in[0,i]\rightarrow s[j\dots i] j∈[0,i]→s[j…i]是字典串,进行更新 d p [ i ] dp[i] dp[i]。

所以关键点就在怎么找到 d p [ j ] dp[j] dp[j]。

因为 T r i e Trie Trie是储存字符串的前缀信息的结构。

这时我们考虑将每个字典串逆序存到字典树 T r i e Trie Trie里,这样每次就可以从 i i i开始向左查找。类似于查找以 i i i结尾的后缀。

然后我们就可以进行状态转移了: d p [ i ] = m i n ( d p [ i ] , d p [ j ] ) dp[i]=min(dp[i],dp[j]) dp[i]=min(dp[i],dp[j])

class Trie{
public:
Trie *next[26]={nullptr};
bool isEnd;
Trie(){
isEnd=false;
}
void insert(string s){
Trie * pos=this;
for(int i=s.length()-1;i>=0;i--){
int t=s[i]-'a';
if(pos->next[t]==nullptr){
pos->next[t]=new Trie();
}
pos=pos->next[t];
}
pos->isEnd=true;
}
};
class Solution {
public:
int respace(vector<string>& di, string s) {
int inf=0x3f3f3f3f,n=s.size();
Trie * root=new Trie();
for(auto str:di)
root->insert(str);
vector<int>dp(n+1,inf);
dp[0]=0;
for(int i=1;i<=n;i++){
dp[i]=dp[i-1]+1;
Trie *pos=root;
for(int j=i;j>=1;j--){
int t=s[j-1]-'a';
if(pos->next[t]==nullptr)
break;
else if(pos->next[t]->isEnd){
if(dp[j-1]<dp[i]) dp[i]=dp[j-1];
}
if(!dp[i]) break;
pos=pos->next[t];
}
}
return dp[n];
}
};