求最长/最大
1. 无重复字符的最长子串
维护一个动态滑动窗口,当新入的字符已经存在时,收缩左区间直到该字符不重复
class Solution {
public int lengthOfLongestSubstring(String S) {
char[] s = S.toCharArray();
int ans = 0, left = 0;
boolean[] had = new boolean[128];
for (int right = 0; right < s.length; right++) {
char c = s[right];
while (had[c]) {
had[s[left++]] = false;
}
had[c] = true;
ans = Math.max(ans, right - left + 1);
}
return ans;
}
}
2. 每个字符最多出现两次的最长子字符串
在上一题的基础上稍微改动,允许一个字符出现两次,先将字符加入到区间当中,再来判断是否超过两个重复的字符,如果是则收缩左区间直到该字符最多仅出现两次
class Solution {
public int maximumLengthSubstring(String S) {
int ans = 0, left = 0;
char[] s = S.toCharArray();
int[] has = new int[128];
for (int right = 0; right < s.length; right++) {
char c = s[right];
has[c]++;
while (has[c] > 2) {
has[s[left++]]--;
}
ans = Math.max(ans, right - left + 1);
}
return ans;
}
}
3. 删掉一个元素以后全为 1 的最长子数组
删除一个元素以后全为 1 的最长子数组,即求最多含有 1 个 0 的最长子数组。维护一个动态滑动窗口,当 0 的数量超过 1 个时收缩左区间
class Solution {
public int longestSubarray(int[] nums) {
int ans = 0, left = 0, count = 0;
for (int right = 0; right < nums.length; right++) {
if (nums[right] == 0) count++;
while (count > 1) {
if (nums[left++] == 0) {
count--;
}
}
ans = Math.max(ans, right - left + 1);
}
return ans - 1;
}
}
4. 尽可能使字符串相等
维护一个动态的滑动窗口,窗口的值为两个字符串之间的差值,限制为差值之和最多为 maxCost
使用一个 sumCost 记录当前窗口的差值和,当达到阈值时收缩左边界(left++)
class Solution {
public int equalSubstring(String S, String T, int maxCost) {
int ans = 0, left = 0, sumCost = 0;
char[] s = S.toCharArray(), t = T.toCharArray();
for (int right = 0; right < s.length; right++) {
sumCost += Math.abs(s[right] - t[right]);
while (sumCost > maxCost) {
sumCost -= Math.abs(s[left] - t[left]);
left++;
}
ans = Math.max(ans, right - left + 1);
}
return ans;
}
}
5. 找到最长的半重复子字符串
用 count 记录相邻字符相等的数目,当达到阈值(即大于 1 对)时,收缩左边界直到最多仅有 1 对相邻相等的字符
class Solution {
public int longestSemiRepetitiveSubstring(String S) {
char[] s = S.toCharArray();
int ans = 0, left = 0, count = 0;
if (s.length == 1)
return 1;
for (int right = 1; right < s.length; right++) {
if (s[right] == s[right - 1]) {
count++;
}
while (count > 1) {
if (s[left] == s[left + 1]) {
count--;
}
left++;
}
ans = Math.max(ans, right - left + 1);
}
return ans;
}
}