这是google onsite的一个题目, 说是一个无限的0/1字符串流, 给定一个字符串如”110010″, 求到当前为止, 在字符流中出现了多少次这种字符.
一开始想到dp来做, 然后画了一下转移方程感觉不对, 然后又感觉越看越像是KMP, 仔细分析可以发现, 其思路就是求当前字符流的后缀与给定的字符串相等即可. 按照正常的思路即取与给定字符串长度相等的字符串, 比较是否相等即可, 这种方式的时间复杂为O(mn), 其中m为给定字符串, n长度为字符流长度. 利用KMP可以优化至O(n).
关于KMP, 我也不想仔细多说, 因为要说清楚很麻烦. 其主要思路是先对pattern字符串求每一位后缀与前缀的匹配长度, 然后在pattern[k]与str[i]进行匹配的时候, 如果当前一位不相等, 那么pattern字符串回退到与pattern[i-1]位后缀相等的前缀的后一位(看不懂就算了).
代码如下:
class Solution {
public:
int getNext(vector<int>& next, string& str)
{
int len = str.size(), k = 0;
for(int i = 1; i < len; i++)
{
while(k>0 && str[i]!= str[k]) k = next[k-1];
next[i] = (k+=str[i]== str[k]);
}
return next[len-1];
}
int match(string& str, string& pattern, vector<int>& next)
{
int ans = 0, len1 = str.size(), len2 = pattern.size(), k =0;
for(int i = 0; i < len1; i++)
{
while(k > 0 &&str[i] != pattern[k]) k = next[k-1];
k += (str[i] == pattern[k]);
if(k == len2) ans++;
}
return ans;
}
int count() {
string str = "11001100110011111", pattern = "1100";
vector<int> next(pattern.size(), 0);
getNext(next, pattern);
return match(str, pattern, next);
}
};