面试题17.13.回复空格
要找到最少的未确定的字符数,使用动态规划的方法,用数组dp[i]来确定截止位置i的未确定字符数。遍历无空格语句sentence,对于第i个位置,未确定字符数为dp[i]=dp[i-1]+1,然后再判断,是否存在j,使得区间(i,j)中的字符串存在于字符串表(即字典)中,如果存在,那么dp[i]=min(dp[i],dp[j-1]),最后返回dp[sentence.size()]。
那么,现在的问题是,如何确定一个字符串是否在字典中呢?这里采用Rabin-Karp字符串编码的方式,赋予每个字符串自己的数值,使用并查集进行查找。代码如下:
class Solution {
public:
using LL=long long;
static const LL MOD=1LL<<31-1;//用于取余
static const LL Base=31;//31进制
int getHash(const string& s) { //得到唯一编码
LL hashValue=0;
for(int i=s.size()-1;i>=0;i--) {
hashValue=hashValue*Base+s[i]-'a'+1;//按Base进制转化成十进制
hashValue%=MOD;//避免因为字符串太长而溢出,取余
//只要MOD够大……不同字符串取余撞上的可能性就很小
}
return hashValue;
}
int respace(vector<string>& dictionary, string sentence) {
unordered_set<LL> hashMap;
int n=dictionary.size();
for(int i=0;i<n;i++) {//将字典里的单词转化为十进制数存在并查集中
hashMap.insert(getHash(dictionary[i]));
}
vector<int> dp(sentence.length()+1,sentence.length());//动态规划数组
dp[0]=0;
for(int i=1;i<=sentence.length();i++) {
dp[i]=dp[i-1]+1;
LL hash_value=0;
for(int j=i;j>=1;j--) {//每一个字符向前查找
//计算第j到第i个数的编码值
hash_value=hash_value*Base+(int)(sentence[j-1]-'a')+1;
hash_value%=MOD;
if(hashMap.find(hash_value)!=hashMap.end()) {//编码值在并查集中
//未定义的最小字符数
dp[i]=min(dp[i],dp[j-1]);
}
}
}
return dp[sentence.length()];
}
};
时间复杂度O(|dictionary|+n2),空间复杂度O(n+p),其中,n为sentence的长度,p为字典中单词个数。
官答还有另一种解法:字典树方法,来解决查找字符串问题。