LeetCode 滑动窗口题型练习(持续更新)

LeetCode 滑动窗口题型练习

字符串的排列

题目

给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。

换句话说,第一个字符串的排列之一是第二个字符串的子串。

示例1:

输入: s1 = “ab” s2 = “eidbaooo”
输出: True
解释: s2 包含 s1 的排列之一 (“ba”).

示例2:

输入: s1= “ab” s2 = “eidboaoo”
输出: False

注意:

输入的字符串只包含小写字母
两个字符串的长度都在 [1, 10,000] 之间

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/permutation-in-string
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

代码

	public static boolean checkInclusion(String s1, String s2) {
        if (s1 == null || s2 == null || s1.length() == 0 || s2.length() == 0 || s1.length() > s2.length()){
            return false ;
        }

        char[] chars1 = s1.toCharArray() ;
        char[] chars2 = s2.toCharArray() ;
        //s1中字符的数量记录
        int[] map1 = new int[26] ;
        //s2中字符的数量记录
        int[] map2 = new int[26] ;
        //s1和s2中相同字符对应数量相等的记录
        int count = 0 ;
        for (int i=0 ; i<chars1.length ; i++){
            map1[chars1[i] - 'a'] ++ ;
            //初始化第一个窗口
            map2[chars2[i] - 'a'] ++ ;
        }
        //先判断第一个窗口与s1的对应
        for (int i=0 ; i<26 ; i++){
            if (map1[i] == map2[i]){
                count ++ ;
            }
        }
        int r , l ;
        int len = chars2.length - chars1.length ;
        for (int i=0 ; i<len ; i++){
            r = chars2[i + chars1.length] - 'a' ;
            l = chars2[i] - 'a' ;
            if (count == 26){
                return true ;
            }
            //核心
            //右边加入的在map2中对应++
            map2[r] ++ ;
            if (map1[r] == map2[r]){
                count ++ ;
            }else if (map1[r] == map2[r] - 1){
                count -- ;
            }
            //左边弹出的在map2中对应--
            map2[l] -- ;
            if (map1[l] == map2[l]){
                count ++ ;
            }else if (map1[l] == map2[l] + 1){
                count -- ;
            }
        }

        return count == 26 ;
    }

替换后的最长重复字符

题目

给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,总共可最多替换 k 次。在执行上述操作后,找到包含重复字母的最长子串的长度。

注意:
字符串长度 和 k 不会超过 104。

示例 1:

输入:
s = “ABAB”, k = 2

输出:
4

解释:
用两个’A’替换为两个’B’,反之亦然。
示例 2:

输入:
s = “AABABBA”, k = 1

输出:
4

解释:
将中间的一个’A’替换为’B’,字符串变为 “AABBBBA”。
子串 “BBBB” 有最长重复字母, 答案为 4。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-repeating-character-replacement
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

代码

	public int characterReplacement(String s, int k) {
        if (s == null || s.length() == 0){
            return 0 ;
        }
        int left = 0 ;
        int right = 0 ;
        int historyMax = 0 ;
        //记录当前窗口中每种字符的个数
        int[] dp = new int[26] ;
        //思路:
        //当前窗口是遍历过的多大的窗口,如果当前内容非法,就移动窗口。如果当前的窗口不违法,扩容。
        for (right = 0 ; right < s.length() ; right ++){
            //
            dp[s.charAt(right) - 'A'] ++ ;
            //当前窗口最多的字符
            historyMax = Math.max(historyMax , dp[s.charAt(right) - 'A']) ;
            //窗口违法
            if (historyMax +k < right - left + 1){
                dp[s.charAt(left) - 'A'] -- ;
                left ++ ;
            }
        }

        return s.length() - left ;
    }

最大连续1的个数

题目

给定一个由若干 0 和 1 组成的数组 A,我们最多可以将 K 个值从 0 变成 1 。

返回仅包含 1 的最长(连续)子数组的长度。

示例 1:

输入:A = [1,1,1,0,0,0,1,1,1,1,0], K = 2
输出:6
解释:
[1,1,1,0,0,1,1,1,1,1,1]
粗体数字从 0 翻转到 1,最长的子数组长度为 6。
示例 2:

输入:A = [0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1], K = 3
输出:10
解释:
[0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1]
粗体数字从 0 翻转到 1,最长的子数组长度为 10。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/max-consecutive-ones-iii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

代码

	public int longestOnes(int[] A, int K) {
        if (A == null || A.length == 0){
            return 0 ;
        }
        int historyMax = 0 ;
        int left = 0 ;
        int right = 0 ;
        int[] dp = new int[2] ;
		//类似于上一道题
        for ( ; right < A.length ; right ++){
            dp[A[right]] ++ ;
            historyMax = Math.max(historyMax , dp[1]) ;
            if (historyMax + K < right - left + 1){
                dp[A[left]] -- ;
                left ++ ;
            }
        }
        return historyMax + K < A.length ? historyMax + K : A.length ;
    }

可获得的最大点数

题目

张卡牌 排成一行,每张卡牌都有一个对应的点数。点数由整数数组 cardPoints 给出。

每次行动,你可以从行的开头或者末尾拿一张卡牌,最终你必须正好拿 k 张卡牌。

你的点数就是你拿到手中的所有卡牌的点数之和。

给你一个整数数组 cardPoints 和整数 k,请你返回可以获得的最大点数。

示例 1:

输入:cardPoints = [1,2,3,4,5,6,1], k = 3
输出:12
解释:第一次行动,不管拿哪张牌,你的点数总是 1 。但是,先拿最右边的卡牌将会最大化你的可获得点数。最优策略是拿右边的三张牌,最终点数为 1 + 6 + 5 = 12 。
示例 2:

输入:cardPoints = [2,2,2], k = 2
输出:4
解释:无论你拿起哪两张卡牌,可获得的点数总是 4 。
示例 3:

输入:cardPoints = [9,7,7,9,7,7,9], k = 7
输出:55
解释:你必须拿起所有卡牌,可以获得的点数为所有卡牌的点数之和。
示例 4:

输入:cardPoints = [1,1000,1], k = 1
输出:1
解释:你无法拿到中间那张卡牌,所以可以获得的最大点数为 1 。
示例 5:

输入:cardPoints = [1,79,80,1,1,1,200,1], k = 3
输出:202

提示:

1 <= cardPoints.length <= 10^5
1 <= cardPoints[i] <= 10^4
1 <= k <= cardPoints.length

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-points-you-can-obtain-from-cards
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

代码

 	public int maxScore(int[] cardPoints, int k) {
        
        if (cardPoints == null || cardPoints.length == 0 || k == 0){
            return 0 ;
        }
        //构造第一个窗口
        int size = cardPoints.length - k ;
        int count = 0 ;
        int min = 0 ;
        int sum = 0 ;
        for (int i=0 ; i<size ; i++){
            count += cardPoints[i] ;
        }
        sum = count ;
        min = count ;
        for (int i=size ; i < cardPoints.length ; i++){
            count -= cardPoints[i - size] ;
            count += cardPoints[i] ;
            min = Math.min(min , count) ;
            sum += cardPoints[i] ;
        }
        return sum - min ;
    }

满足条件的子序列数目(超时)

题目

给你一个整数数组 nums 和一个整数 target 。

请你统计并返回 nums 中能满足其最小元素与最大元素的 和 小于或等于 target 的 非空 子序列的数目。

由于答案可能很大,请将结果对 10^9 + 7 取余后返回。

示例 1:

输入:nums = [3,5,6,7], target = 9
输出:4
解释:有 4 个子序列满足该条件。
[3] -> 最小元素 + 最大元素 <= target (3 + 3 <= 9)
[3,5] -> (3 + 5 <= 9)
[3,5,6] -> (3 + 6 <= 9)
[3,6] -> (3 + 6 <= 9)
示例 2:

输入:nums = [3,3,6,8], target = 10
输出:6
解释:有 6 个子序列满足该条件。(nums 中可以有重复数字)
[3] , [3] , [3,3], [3,6] , [3,6] , [3,3,6]
示例 3:

输入:nums = [2,3,3,4,6,7], target = 12
输出:61
解释:共有 63 个非空子序列,其中 2 个不满足条件([6,7], [7])
有效序列总数为(63 - 2 = 61)
示例 4:

输入:nums = [5,2,4,1,7,6,8], target = 16
输出:127
解释:所有非空子序列都满足条件 (2^7 - 1) = 127

提示:

1 <= nums.length <= 10^5
1 <= nums[i] <= 10^6
1 <= target <= 10^6

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-subsequences-that-satisfy-the-given-sum-condition
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

代码

	public int numSubseq(int[] nums, int target) {
        if (nums == null || nums.length == 0){
            return 0 ;
        }
        //双指针
        //1.sort一下
        //2.
        //3.while left <= right
        //4.找到right最大位置
        //5.计算子序列的个数
        //6.left ++
        long mod = 1_0000_0000_7 ;
        long count = 0 ;

        Arrays.sort(nums);

        int left = 0 ;
        int right = nums.length - 1 ;
        while(left <= right){
            //找到right的位置
            while(right >= 0 &&nums[left] + nums[right] > target){
                right -- ;
            }
            //System.out.println("范围:" + nums[left] + " - " + nums[right]);
            //cal
            int l = right - left + 1 ;
            if (right < left){
                break ;
            }
            count += cal(l , mod);
            //System.out.println("总数量:"+count);
            left ++ ;
        }
        return (int) (count % mod);
    }

	//移位的时候可能会溢出
    public long cal(int l , long mod){
        long k = 1 ;
        for (int i=0 ; i<l-1 ; i++){
            k = k << 1 ;
            if (k > mod){
                k = k % mod ;
            }
        }
        return k ;
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值