Leetcode 每种字符至少取 K 个 Java滑动窗口

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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哇塞大嘴好帅(DaZuiZui)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值