考虑字符串s是“abcdefghijklmnopqrstuvwxyz”的无限环绕字符串,所以s将如下所示:“... zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd ....”。
现在我们有另一个字符串p。 你的工作是找出s中有多少个唯一的非空子串p。 特别是,您的输入是字符串p,您需要输出字符串s中p的不同非空子串的数量。注意:p只包含小写英文字母,p的大小可能超过10000。
Example 1:
Input: "a" Output: 1 Explanation: Only the substring "a" of string "a" is in the string s.
Example 2:
Input: "cac" Output: 2 Explanation: There are two substrings "a", "c" of string "cac" in the string s.
Example 3:
Input: "zab" Output: 6 Explanation: There are six substrings "z", "a", "b", "za", "ab", "zab" of string "zab" in the string s.
思路:
这个题的目标串z和a是相连的,即"...zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd...."当a的前面是z的时候依然可以看成是连续的子串。在算法实现的时候,最大的问题就是出现类似"abcabcd"的时候
前面的"abc"会出现的子串有:a,b,c,ab,bc,abc;
后面的“abcd”会出现的子串有:a,b,c,d,ab,bc,cd,abc,bcd,abcd,在应用普通方法进行累加的时候,会出现重复统计,当时第一反应是建立一个hashmap,但是这样空间复杂度很大且还要将每一个出现过的子串添加到hashmap中,实现难度较大;
但是,换个角度思考,在字符串种p中,出现的字母也就是26个,如果我们求得以每个字母结尾的子串,然后再将它们加起来,就可以得到所有的子串,比如说:
example: abcabcd
longest(0) = 1, ==> 第一个字符a结尾的最大子串为a本身,即1 len=1
longest(1) = 2 ==> 第二个字符b结尾的最大子串为:b结尾的b,ab这个子串 len=len++=2
longest(2) = 3 ==> 第三个字符c结尾的最大子串为:以c结尾的c,bc,abc这个子串 len=len++=3
longest(3) = 1, ==> 第四个字符a结尾的最大子串为a本身,因为他的前一个字符不是z(相当于断了) len=1
longest(4) = 2 ==> 第五个字符b结尾的最大子串为:以b结尾的b,ab这个子串 len=len++=2
longest(5) = 6 ==> 第六个字符c结尾的最大子串为:以c结尾的c,bc,abc这个子串 len=len++=3
longest(6) = 4 ==> 第七个字符d结尾的最大子串为:以d结尾的d,cd,bcd,abcd这个子串 len=len++=4这样问题就可以变得简单了。此时就是如何求得longest(a)。对于上述的"abcabcd"我们发现对数组进行了两次覆盖,这时我们会取较大值,因为只要是连续出现的以a为结尾的字符串的形式一定是"...xyza..."所以长度长的串一定包含长度短的所有子串,就像abcd的子串包含abc的所有子串一样。。。
参考代码:
class Solution {
public:
int findSubstringInWraproundString(string p) {
int len = 0;
int res = 0;
int *dp = new int[26];
for (int i = 0; i < 26; i++) {
dp[i] = 0;
}
for (int i = 0; i < p.size(); i++) {
if (i > 0 && ((p[i] - p[i - 1]) == 1 || (p[i - 1] - p[i]) == 25)) {
len++;
}
else {
len = 1;
}
dp[p[i] - 'a'] = max(dp[p[i]-'a'], len);
}
for (int i = 0; i < 26; i++) {
res += dp[i];
}
delete[] dp;
return res;
}
};