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的时候去删掉这个位
最后哦,判断种类个数也可以用二分优化一下。
优化算法:利用位运算改进字符串最长'好'子串查找

本文介绍了一种将字符串最长'好'子串问题中的数组压缩到两个整数的优化方法,通过位运算实现快速判断和减少空间复杂度。滑动窗口策略结合位操作,降低时间复杂度至O(n)。
884

被折叠的 条评论
为什么被折叠?



