Leetcode 每种字符至少取 K 个 Java滑动窗口
Ideas
/**
* 思路:
* 首先先查看下这个字符串是否合法是否能满足每个字符出现了>=k次
* 题意是从左侧拿或者从右侧拿,那么我们就求一下中间不拿的部分,如
* aabaaaacaabc 我们求 aab aaaa caabc 中间的4个a,
* 比如拿a字符来说 我们先统计一下这个字符a出现了7次,那么我们需要去截取的中间的部分a最多只能出现4次, b c同理
* 那么我们可以用滑动窗口来遍历这个字符串 l = 0 , r = 0,记录这个窗口之间每个字符出现的次数
* 如果某个字符出现的次数大于了他能出现的最大次数,那么我们就l下标移除,依次类推
* 每一次r指针滑动的时候我们都对窗口计算一下当前这个窗口的长度 r - l + 1记录一下最大的值
* 当我们窗口遍历完毕 n - 我们记录的最大值的结果就是我们需要从左侧和右侧拿取的数量
*/
首先我们要记录一下这个字符串每个字符出现的次数
//用来记录a b c出现的个数
int[] subarr = new int[3];
//记录字符串中每个字符存在的次数
for (char aChar : chars) {
subarr[aChar - 'a']++;
}
记录需要截取的字符串每个字母出现的最大的次数和判断一下s字符串是否合法
//记录需要截取的字符串每个字母出现的最大的次数
int al = subarr[0] - k,bl = subarr[1] - k , cl = subarr[2] - k;
//查看这个字符串是否合法
if (al < 0 || bl < 0 || cl < 0 ) return -1;
我们晴空我们subarr数组,拿他作为我们窗口记录每个字符出现的个数
//需要截取的字符串最大长度
int max = Integer.MIN_VALUE;
//用来记录当前字符串截取的个数
subarr = new int[3];
/**
* 去寻找中间需要截取的字符串
*/
for (int l = 0, r = 0; r < n; r++) {
//记录需要截取的字符
subarr[chars[r] - 'a']++;
//当前某一个字符出现的个数大于应该截取的区域最大个数
while (check(subarr,al,bl,cl)){
subarr[chars[l++] -'a']--;
}
max = Math.max(max,r-l+1);
}
校验方法
/**
* 查看需要截取的字符串个数是否大于每个字符应该出现的最大数量,如果是则返回true
* @param arr
* @param al
* @param bl
* @param cl
* @return
*/
public boolean check(int[] arr,int al,int bl,int cl){
return arr[0] > al || arr[1] > bl || arr[2] > cl;
}
code
import jdk.nashorn.api.scripting.ScriptUtils;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
public class P6270 {
public static void main(String[] args) {
System.out.println(new P6270().takeCharacters("a", 1));
}
/**
* 思路:
* 首先先查看下这个字符串是否合法是否能满足每个字符出现了>=k次
* 题意是从左侧拿或者从右侧拿,那么我们就求一下中间不拿的部分,如
* aabaaaacaabc 我们求 aab aaaa caabc 中间的4个a,
* 比如拿a字符来说 我们先统计一下这个字符a出现了7次,那么我们需要去截取的中间的部分a最多只能出现4次, b c同理
* 那么我们可以用滑动窗口来遍历这个字符串 l = 0 , r = 0,记录这个窗口之间每个字符出现的次数
* 如果某个字符出现的次数大于了他能出现的最大次数,那么我们就l下标移除,依次类推
* 每一次r指针滑动的时候我们都对窗口计算一下当前这个窗口的长度 r - l + 1记录一下最大的值
* 当我们窗口遍历完毕 n - 我们记录的最大值的结果就是我们需要从左侧和右侧拿取的数量
*/
public int takeCharacters(String s, int k) {
int n = s.length();
char[] chars = s.toCharArray();
//用来记录a b c出现的个数
int[] subarr = new int[3];
//记录字符串中每个字符存在的次数
for (char aChar : chars) {
subarr[aChar - 'a']++;
}
//记录需要截取的字符串每个字母出现的最大的次数
int al = subarr[0] - k,bl = subarr[1] - k , cl = subarr[2] - k;
//查看这个字符串是否合法
if (al < 0 || bl < 0 || cl < 0 ) return -1;
//需要截取的字符串长度
int max = Integer.MIN_VALUE;
//用来记录当前字符串截取的个数
subarr = new int[3];
/**
* 去寻找中间需要截取的字符串
*/
for (int l = 0, r = 0; r < n; r++) {
//记录需要截取的字符
subarr[chars[r] - 'a']++;
//当前某一个字符出现的个数大于应该截取的区域最大个数
while (check(subarr,al,bl,cl)){
subarr[chars[l++] -'a']--;
}
max = Math.max(max,r-l+1);
}
return n - max;
}
/**
* 查看需要截取的字符串个数是否大于每个字符应该出现的最大数量,如果是则返回true
* @param arr
* @param al
* @param bl
* @param cl
* @return
*/
public boolean check(int[] arr,int al,int bl,int cl){
return arr[0] > al || arr[1] > bl || arr[2] > cl;
}
}