1156. 单字符重复子串的最大长度
感觉这道题,双指针的思路很好想,但是要直接实现,对我而言还是有一些磕磕绊绊(还是题做少了qaq)。
思路是这样的,比如字符串序列为: aaabaaaba
那么一开始,可以用指针 i 指向第一个值(i = 0,i 指向字母 a),然后再定义指针 j ,从 i 开始向后寻找不等于 i 所指向的值(此处找的是不等于字母 a 的)。找到后停下,此时标记区间 [i, j) 为区间 L,长度是(j-i),该区间中只有字母 a。
然后跳过 j ,再定义指针 k 从 j 后一个开始找,直到再次找到和 i 指向的值不同的值(即k也向后走,直到k指向的值不为字母 a 才停止。)标记区间 (j, k) 为区间 R,此时区间R当中也都是字母 a。
L和R区间内全部都是与 i 所指向的值相同的值。L 和 R 之间还间隔了一个数。此时,是不是 L+R+1 的值就是最长区间呢?答案是不一定!
此时就要比较,L+R+1与 i 所指向的字母在字符串中出现的总个数之间的大小了。
要知道,L 和 R 之间还有一个位置上的值(即 j 所在的位置)不是 a,L和R其实并没有脸上。那么能否从别的位置调换一个 a 过来,自然要看别的位置还有没有 a。如果所有的a都在L+R当中了,那就没有多余的a来替换 j 的位置,那么这样,L和R也就连不上了。
即:min(L+R+1, count(text[i])),才是对于 i 所指向的值的最长连续区间。对于每一个 i ,都更新它最长连续区间结果的较大值。那么即是:
res = max(res, min(L+R+1, count(text[i])) )
每次更新 i,让 i = j,再让 j = i,即可。
AC的代码如下:
class Solution {
Map<Character, Integer> map = new HashMap<>(); //记录字符串中各个字符出现的个数
int res;
void init(String text) {
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
map.put(c, map.getOrDefault(c, 0) + 1);
}
}
public int maxRepOpt1(String text) {
init(text);
int tlen = text.length();
int i = 0;
int j = 0;
while(j < tlen) {
char iletter = text.charAt(i);
int itimes = map.get(iletter);
while(j < tlen && text.charAt(j) == text.charAt(i)) j++;
int l = j-i; // l = (j-1)-i+1;
int k = j+1;
while(k < tlen && text.charAt(k) == text.charAt(i)) k++;
int r = k-j-1; // r = (k-1)-(j+1)+1;
res = Math.max(res, Math.min(l+r+1, itimes));
i = j; //更新
j = i;
}
return res;
}
}
这里还要补充谈一下,init()方法。
void init(String text) {
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
map.put(c, map.getOrDefault(c, 0) + 1);
}
}
它的作用是初始化map,记录每个字符出现的个数。这里用一个 map.getOrDefault(c, 0)+1 就好了。我刚开始忘记了map有这个方法,所以写得很麻烦。getOrDefault()的第二个参数,就是我们可以自己指定的默认值。如果map中还没有我们要的key,那就返回0;如果有,那就返回对应key的value。
其中犯过一些小问题。一个是每次循环结束,更新 i 的时候, 让 i = k+1.
很显然,这样通不过全部的用例("bbababaaaa"),i是跳着走的,把中间的 j 位置跳过去了(而 j 位置上的元素恰好是不同的那个)。然后我改成 i++,这样也是可以的,但是没必要。让 i = j即可。
还有一次WA是,把 j 初始化成了 i+1.结果 while 循环进不去,当字符串只有一个 "a" 的时候,就错误了。应该输出1,我这只能输出0.