滑动窗口--方向相同的双指针思路

大致思路如下:

        给定一个序列,定义两个指针left,right,根据题意定义区间[left,right]之前的衡量指标f,比如区间和,乘积以及其他等。开始时left=right=0,计算指标f,left先不变,right往右边移动,更新f的值,当f符合一定条件时,left往右边移动,此时相当于区间变小,更新f的值,如果f一直符合题意,则left一直往右移动,如果f不符合题意,则left不变,继续移动right位置。如此往复,相当于一个滑动窗口把整个序列遍历了一遍,在整个过程中,当找到区间[left,right]时,可以记录过程中,最终获取极值。

来几道练习题

/**
 * 给定一个含有n个正整数的数组和一个正整数 target 。
 *
 * 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组[numsl, numsl+1, ..., numsr-1, numsr] ,
 * 并返回其长度。如果不存在符合条件的子数组,返回 0 。
 *
 * */
public int minSubArrayLen(int target, int[] nums) {
        int left = 0;
        int right = 0;
        int sum = 0;
        int min = Integer.MAX_VALUE;
        // 如果总和小于target 则直接返回0
        int total = Arrays.stream(nums).sum();
        if (total < target) return 0;
        // 双指针 右指针不停向右探索 一直找到符合条件的位置
        // 此时左指针尝试向右 搜索更大的位置
        for (right=0; right<nums.length; right++) {
            sum = sum + nums[right];
            while (sum >= target) {
                min = Math.min(min, right-left+1);
                sum = sum - nums[left];
                left++;
            }
        }
        return min;
    }
/**
 * 给定一个正整数数组 nums和整数 k ,请找出该数组内乘积小于 k 的连续的子数组的个数。
 * */
public int numSubarrayProductLessThanK(int[] nums, int k) {
        int left = 0;
        int right = 0;
        int acc = 1;
        int cnt = 0;
        for (right=0; right<nums.length; right++) {
            acc = acc * nums[right];
            while (acc >= k && left <= right) {
                acc = acc / nums[left];
                left++;
            }
            if (left <= right) {
                cnt = cnt + (right - left + 1);
            }
        }
        return cnt;
    }
/**
 * 给定一个字符串 s ,请你找出其中不含有重复字符的 最长连续子字符串 的长度。
 * s 由英文字母、数字、符号和空格组成
 * */
public int lengthOfLongestSubstring(String s) {
        int max = 0;
        Map<Character, Integer> map = new HashMap<>();
        int left = 0;
        int right = 0;
        for ( ; right < s.length(); right++) {
            map.put(s.charAt(right), map.getOrDefault(s.charAt(right), 0) + 1);
            while (!allLessThanOne(map) && left <= right) {
                map.put(s.charAt(left), map.getOrDefault(s.charAt(left), 0) - 1);
                left++;
            }
            max = Math.max(max, right - left + 1);
        }
        return max;
    }

    private boolean allLessThanOne(Map<Character, Integer> map) {
        return map.values().stream().filter(num -> num > 1).count() == 0;
    }
/**
 * 给定两个字符串 s 和t 。返回 s 中包含t的所有字符的最短子字符串
 * 如果 s 中不存在符合条件的子字符串,则返回空字符串 ""
 * 如果 s 中存在多个符合条件的子字符串,返回任意一个
 * 注意: 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量
 * s 和 t 由英文字母组成
 * */
public String minWindow(String s, String t) {
        if (s.length() < t.length()) return "";
        Map<Character, Integer> map = new HashMap<>();
        for (char ch: t.toCharArray()) {
            map.put(ch, map.getOrDefault(ch, 0) + 1);
        }
        int left = 0;
        int right = 0;
        int minLength = Integer.MAX_VALUE;
        int minLeft = 0, minRight = 0;
        for ( ; right < s.length(); right++) {
            map.put(s.charAt(right), map.getOrDefault(s.charAt(right), 0) - 1);
            while (allLessEqualThanOne(map) && left <= right) {
                if ((right-left) < minLength) {
                    minLeft = left;
                    minRight = right;
                    minLength = minRight - minLeft;
                }
                map.put(s.charAt(left), map.getOrDefault(s.charAt(left), 0) + 1);
                left++;
            }
        }
        return minLength == Integer.MAX_VALUE ? "" : s.substring(minLeft, minRight + 1);
    }

    private boolean allLessEqualThanOne(Map<Character, Integer> map) {
        return map.values().stream().filter(num -> num >= 1).count() == 0;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值