窗口滑动算法

窗口滑动算法

简介

滑动窗口算法思想是非常重要的一种思想,可以用来解决数组,字符串的子元素问题。它可以将嵌套循环的问题,转换为单层循环问题,降低时间复杂度,提高效率。

滑动窗口的思想非常简单,它将子数组(子字符串)理解成一个滑动的窗口,然后将这个窗口在数组上滑动,在窗口滑动的过程中,左边会出一个元素,右边会进一个元素,然后只需要计算当前窗口内的元素值即可。

可用滑动窗口思想解决的问题,一般有如下特点:

  1. 窗口内元素是连续的。就是说,抽象出来的这个可滑动的窗口,在原数组或字符串上是连续的。

  2. 窗口只能由左向右滑动,不能逆过来滑动。就是说,窗口的左右边界,只能从左到右增加,不能减少,即使局部也不可以。

算法思想

1.定义两个变量:right和right,用来表示两个边界。[left,right]表示窗口
2.首先right边界先扩张,到达指定的位置(根据题目来定),然后left开始扩张,直到指定的位置(依据题目来定)
3.重复上述步骤,直到right走到数组或者字符串的尾部为止

算法实现

left,right := 0,0 // 左右指针

// 窗口右边界滑动
for right < length {
  window.add(s[right])      // 右元素进窗
  right++                   // 右指针增加

  // 窗口满足条件
  for valid(window) && left<right {
    ...                      // 满足条件后的操作
    window.remove(arr[left]) // 左元素出窗
    left++                   // 左指针移动,直到窗口不满足条件
  }
}

注意:
.滑动窗口适用的题目一般具有单调性
.滑动窗口、双指针、单调队列和单调栈经常配合使用

下面为例子:

1.无重复字符的最长子串

题目描述:给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例1:
	输入: s = "abcabcbb"
	输出: 3 
	解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3
示例1:
	输入: s = "bbbbb"
	输出: 1
	解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:
	输入: s = "pwwkew"
	输出: 3
	解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串
思路
设置right和left,并且设置一个max用来求每次的最大值,使用hashSet来存放临时的子串,当right找到重复的元素时,right停止扩张,直到set删除那个重复元素为止。
代码实现
       //维护当前最长不重复字符子串
                Set<Character> set = new HashSet<>();
                int left = 0;
                int right = 0;
                int max = 0;
                while(right<s.length()){
                    if(!set.contains(s.charAt(right))){
                        //未查到重复字符就一直加,right右移
                        set.add(s.charAt(right));
                        right++;
                    }else{
                        //right查到重复字符先不动,left右移,set删left经过的字符,直到重复的这个字符删掉为止
                        set.remove(s.charAt(left));
                        left++;
                    }
                    //每一次计算当前set子串的长度

                    max = Math.max(max, set.size());
                }
                return max;
            }

2.案例二给定一个整数数组,计算长度为k的连续子数组的最大总和。

	列子:
		输入:arr [] = {100,200,300,400}  k = 2

		输出:700

		解释:300 + 400 = 700

代码实现

 /**
     * 输入:arr [] = {100,200,300,400}  k = 2
     *
     * 输出:700
     *
     * 解释:300 + 400 = 700
     * @param target
     * @param nums
     * @return
     */

    public static void main(String[] args) {
        int[] nums =new int[]{100,200,300,400};
        int result = minSubArrayLen(2, nums);
        System.out.println(result);
    }
    public static int minSubArrayLen (int k, int[] nums){
        int len =  nums.length;

        int maxsum = 0;
        for (int i = 0; i < k; i++) {
            maxsum  = maxsum + nums[i];
        }
        int sum = maxsum;
        for (int i = k; i < len ; i++) {
            sum  = sum +nums[i] - nums[i-k];
            maxsum =  Math.max(sum, maxsum);
        }
        return maxsum;
    }
posted @ 2022-11-12 16:36  wiselee/  阅读(144)  评论(0编辑  收藏  举报