题目
把字符串 s 看作是“abcdefghijklmnopqrstuvwxyz”的无限环绕字符串,所以 s 看起来是这样的:"…zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd…".
现在我们有了另一个字符串 p 。你需要的是找出 s 中有多少个唯一的 p 的非空子串,尤其是当你的输入是字符串 p ,你需要输出字符串 s 中 p 的不同的非空子串的数目。
注意: p 仅由小写的英文字母组成,p 的大小可能超过 10000。
分析
- 暴力解法
一开始用了最笨最直接的方法,所有的子字符串都遍历一遍,用set去重,硬生生的套了4层循环之后,我就知道肯定凉了,果然超时了。 - 记录状态
上面的方法时间复杂度太高了,看了别人的方法之后才明白:
用一个26位数组记录abcde……z每个字母的最多的子字符串的个数,就比如字符串是:abcda,那么a的最多的子字符串个数就是4(a ab abc abcd),也就是从abcd这个连续的字符串的字母个数;那么b也就是3,c也就是2,d就是1;最后还有一个字母a,因为a的最长之前记录为4,又数现在这个是1,4>1,所以不更新。 - 解题步骤
- 先定义数组 int[26] array, 一个int型的start整数,记录连续子字符串的开始。
- 开始遍历p字符串,前一字母和后一字母相差1,则继续遍历,start不动,直到条件不成立:
- 条件不成立时,就要开始记录状态,向对应的array中写入最长字符串个数,start==i,继续遍历……
- 最后将array数组做和。
代码
自己写的代码忒丑,下面有最佳时间的代码。
class Solution {
public int findSubstringInWraproundString(String p) {
int[] arryas = new int[26];
int start = 0;
for (int i = 0; i < p.length()-1; i++) {
if ( i+1 < p.length() && ((p.charAt(i) + 1 == p.charAt(i + 1)) || (p.charAt(i) == 'z' && p.charAt(i + 1) == 'a' ) )){
}else{
int count = i - start + 1;
int j = start;
while (count > 0){
arryas[p.charAt(j)-97] = Math.max(count, arryas[p.charAt(j)-97]);
j++;
count--;
}
start = i+1;
}
}
int count = p.length() - start;
int j = start;
while (count > 0){
arryas[p.charAt(j)-97] = Math.max(count, arryas[p.charAt(j)-97]);
j++;
count--;
}
int sum = 0;
for (int i = 0; i < 26; i++) {
System.out.print(arryas[i] + " ");
sum += arryas[i];
}
System.out.println();
return sum;
}
}
class Solution {
public int findSubstringInWraproundString(String p) {
int[] pSize = new int[p.length()];
int[] count = new int[26];
for (int i = 0; i < p.length() ; i ++) {
pSize[i] = (int) (p.charAt(i) - 'a');
}
int num = 0;
int sum = 0;
for (int i = 0; i < pSize.length; i ++) {
if (i > 0 && (pSize[i - 1] + 1) % 26 == pSize[i] ) {
num ++;
}
else {
num = 1;
}
count[pSize[i]] = Math.max(count[pSize[i]],num);
}
for (int i = 0; i < 26; i ++) {
sum = sum + count[i];
}
return sum;
}
}