n^2暴力模拟
class Solution {
public String longestNiceSubstring(String s) {
int n = s.length();
int ansEnd = -1;
int ansStart = -1;
for (int end = 1; end < n; end++) {
int[] cnt = new int[52];
cnt[change(s.charAt(end))]++;
for (int start = end - 1; start >= 0; start--) {
cnt[change(s.charAt(start))]++;
if (end - start > ansEnd - ansStart && judge(cnt)) {
ansEnd = end;
ansStart = start;
}
}
}
if (ansStart == -1) {
return "";
}
return s.substring(ansStart, ansEnd + 1);
}
// 小写字母对应下标 0 - 25
// 大写字母对应下标 26 - 51
int change(char c) {
if (c >= 'a') {
return c - 'a' + 26;
}
return c - 'A';
}
boolean judge(int[] cnt) {
for (int i = 0; i < 26; i++)
if (cnt[i] != 0 && cnt[i + 26] == 0 || cnt[i] == 0 && cnt[i + 26] != 0)
return false;
return true;
}
}
这里使用了一个大小为52的数组来存储,但实际上可以用位运算来压缩到2个整数,因为一个整数可以表示32位,52位只需要两个整数。并且这样做,比较是否符合要求,只需要O1。我们要做的只是去修改judge和change两个方法。
class Solution {
int upper;
int lower;
public String longestNiceSubstring(String s) {
int n = s.length();
int ansEnd = -1;
int ansStart = -1;
for (int end = 1; end < n; end++) {
upper = 0;
lower = 0;
change(s.charAt(end));
for (int start = end - 1; start >= 0; start--) {
change(s.charAt(start));
if (end - start > ansEnd - ansStart && judge()) {
ansEnd = end;
ansStart = start;
}
}
}
if (ansStart == -1) {
return "";
}
return s.substring(ansStart, ansEnd + 1);
}
void change(char c) {
if (c >= 'a') {
upper |= 1 << c - 'a';
} else {
lower |= 1 << c - 'A';
}
}
boolean judge() {
return lower == upper;
}
}
看了题解,用的是滑动窗口。单纯的使用滑动窗口肯定是不行的,我们没法确定窗口停止的条件。我们很容易观察到,在窗口滑动的过程中,窗口中的元素种类一直在变化,所以如果我们限定了窗口移动的元素种类个数,便可以使用滑动窗口的方法。因为一共有26种元素种类,每次滑动窗口On,所以一共需要26 * n的时间复杂度。
注意,用滑动窗口如果要用位运算,还得统计每个字母出现的次数orz,当为0的时候去删掉这个位
最后哦,判断种类个数也可以用二分优化一下。