将x减到0的最小操作数
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/f682908b57db43f083d349d4a24f4628.png)
思路
- 将x减到0的最小操作数
- target=sum(nums)-x
- windowSum<=target 扩大窗口 right++
- windowSum>target 缩小窗口 left++
- windowSum==target 更新结果值
public int minOperations(int[] nums, int x) {
int left=0,right=0;
int sum=0;
for(int i:nums){
sum+=i;
}
int windowTarget=sum-x,res=Integer.MIN_VALUE,windowSum=0;
while (right<nums.length){
windowSum+=nums[right];
right++;
while (windowSum>windowTarget){
windowSum-=nums[left];
left++;
}
if(windowSum==windowTarget){
res=Math.max(res,right-left);
}
}
return res==Integer.MIN_VALUE?-1:nums.length-res;
}
乘积小于k的子数组
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/9fa9a2d7975990f5ac3204b4a2dc0d53.png)
思路
- 乘积小于k的子数组
- 窗口乘积windowMul
- windowMul<k 扩大窗口 right++
- windowMul>=k缩小窗口 left++
- count+=right-left 更新结果值
public int numSubarrayProductLessThanK(int[] nums, int k) {
int left=0,right=0,count=0;
int windowMul=1;
while (right<nums.length){
windowMul*=nums[right];
right++;
while (left<right && windowMul>=k){
windowMul/=nums[left];
left++;
}
count+=right-left;
}
return count;
}
最大连续1的个数 III
思路
- 最大连续1的个数 III
- 窗口内0有windowZeroCount个
- windowZeroCount<=k 扩大窗口 right++
- windowZeroCount>k缩小窗口 left++
- max_len=Math.max(max_len,right-left) 更新结果值
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/e5ecfa83230420fe9dee8f4d7ccc0453.png)
public int longestOnes(int[] nums, int k) {
int left=0,right=0,windowZeroCount=0;
int max_len=0;
while (right<nums.length){
if(nums[right]==0)
windowZeroCount++;
right++;
while (windowZeroCount>k){
if(nums[left]==0){
windowZeroCount--;
}
left++;
}
max_len=Math.max(max_len,right-left);
}
return max_len;
}
替换后的最长重复字符
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/992385b1dfca3fe5bfd289f264f99ced.png)
思路
- 替换后的最长重复字符
- 对于A-Z的每个字符c,把非字符c的大写字符替换成c,窗口内只能替换k次
- 套用最大连续1的个数 III
- windowCharCount<=k 扩大窗口 right++
- windowCharCount>k缩小窗口 left++
- max_len=Math.max(max_len,right-left) 更新结果值
- 最后得到最大的max_len值为算法输出
public int getRes(String s,int k,char c){
int left=0,right=0,windowCharCount=0;
int max_len=0;
while (right<s.length()){
if(s.charAt(right)==c){
windowCharCount++;
}
right++;
while (right-left-windowCharCount>k){
if(s.charAt(left)==c){
windowCharCount--;
}
left++;
}
max_len=Math.max(max_len,right-left);
}
return max_len;
}
public int characterReplacement(String s, int k) {
int res=0;
for(char c='A';c<='Z';c++){
res=Math.max(res,getRes(s,k,c));
}
return res;
}
存在重复元素 II
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/a75ea9108b366cab640ead674ee88eed.png)
思路
- 存在重复元素 II
- 哈希窗口window存储数组nums元素
- 窗口内存在nums[right] 返回true
- right-left<=k window.add(nums[right]) 扩大窗口 right++
- right-left>k window.remove(nums[left]) 缩小窗口 left++
public boolean containsNearbyDuplicate(int[] nums, int k) {
HashSet<Integer>window=new HashSet<>();
int left=0,right=0;
while (right<nums.length){
if(window.contains(nums[right]))
return true;
window.add(nums[right]);
right++;
while (right-left>k){
window.remove(nums[left]);
left++;
}
}
return false;
}
存在重复元素 III
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/81be42888c193d4b81da7ef0b1d83a1b.png)
思路
- 存在重复元素 III
- TreeSet(window)存储数组nums元素
- 取出window中最接近nums[right]中的最大元素(ceiling)和最小元素(floor)
- 如果两者存在,则判断它们各自与nums[right]的差值的绝对值是否不大于valueDiff,是则返回true
- right-left<=indexDiff window.add(nums[right]) 扩大窗口 right++
- right-left>indexDiff window.remove(nums[left]) 缩小窗口 left++
public boolean containsNearbyAlmostDuplicate(int[] nums, int indexDiff, int valueDiff) {
int left=0,right=0;
TreeSet<Integer>window=new TreeSet<>();
while (right<nums.length){
Integer ceiling=window.ceiling(nums[right]);
if(ceiling!=null && ceiling-nums[right]<=valueDiff)
return true;
Integer floor=window.floor(nums[right]);
if(floor!=null && nums[right]-floor<=valueDiff)
return true;
window.add(nums[right]);
right++;
while (right-left>indexDiff){
window.remove(nums[left]);
left++;
}
}
return false;
}
至少有k个重复字符的最长子串
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/a4e5ee24781f4295524af9a95951c22a.png)
思路
- 至少有k个重复字符的最长子串
- 对于 a-z 26个字符的任意组合,可以出现的子串中各字符的组合种类有26种
- 对于窗口内的子串需要满足的条件是:
1. 字符种类为classes
2. 每种字符最少出现k次 - 当窗口字符种类数windowClassCount不大于classes时,扩大窗口,right++
- 当窗口字符种类数windowClassCount大于classes时,缩小窗口,left++
- 使用变量windowValidCount记录窗口内有多少个字符出现次数至少为k次
- 如果窗口内的子串满足条件1、2(windowValidCount==classes),则更新最大长度max_len=Math.max(max_len,right-left)
public int getMaxLen(String s,int k,int classes){
int left=0,right=0,max_len=0;
int windowClassCount=0,windowValidCount=0;
int[]window=new int[26];
while (right<s.length()){
char c=s.charAt(right);
if(window[c-'a']==0)
windowClassCount++;
window[c-'a']++;
if(window[c-'a']==k)
windowValidCount++;
right++;
while (windowClassCount>classes){
char d=s.charAt(left);
if(window[d-'a']==k)
windowValidCount--;
window[d-'a']--;
if(window[d-'a']==0)
windowClassCount--;
left++;
}
if(windowValidCount==classes)
max_len=Math.max(max_len,right-left);
}
return max_len;
}
public int longestSubstring(String s, int k) {
int res=0;
for(int i=1;i<=26;i++){
res=Math.max(res,getMaxLen(s,k,i));
}
return res;
}