乐趣区

关于算法:滑动窗口法寻找最长子序列

滑动窗口法就是在一直地调整子序列地起始地位与终止地位,从而得出咱们想要的后果。滑动窗口法的起始与终止节点的挪动的目标即为求解子序列的最优化解决,其根本的思路如下:

  1. 定义双指针,初始值统一,双指针之间的内容为所谓的窗口,包含双指针所指的元素。
  2. 确定指针之间的最佳窗口内容的判断条件,即窗口内容扩充、放大的条件。
  3. 优先挪动终止节点,扩充窗口直至恰好满足判断条件,再挪动起始节点一次放大窗口
  4. 再次判断是否符合条件,合乎,此时为一次所求解的子序列,记录所需参数,继续移动起始节点,不合乎,起始节点不动,挪动终止节点至恰好符合条件
  5. 反复第三、第四点,至终止节点达到数组最初一位。
  6. 输入所需参数

外面最为要害的就是节点的挪动,怎么挪动!什么时候挪动!都是须要依据题目理论状况进行考量。

如果,采取暴力做法采取双层 for 循环形式一直循环寻找符合条件的子序列,工夫复杂度为 O(n^2^) , 而如果采纳滑动窗口法将减低至 O(n) , 执行效率大大提高。LeetCode 题目链接:长度最小的数组

题目形容

给定一个含有 n 个正整数的数组和一个正整数 target。

找出该数组中满足其和 ≥ target 的长度最小的 间断子数组 [numsl, numsl+1, …, numsr-1, numsr],并返回其长度。如果不存在符合条件的子数组,返回 0。

示例:

示例 1:

输出:target = 7, nums = [2,3,1,2,4,3]
输入:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

示例 2:

输出:target = 4, nums = [1,4,4]
输入:1

示例 3:

输出:target = 11, nums = [1,1,1,1,1,1,1,1]
输入:0

提醒:

  • 1 <= target <= 109
  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 105

题目剖析

题目简略剖析一下,就是获取合乎序列内数字之和不小于目标值的最小子序列的长度。思路根本如下:

  1. 初始化双指针为 0
  2. 放大、扩充判断条件确定为 sum >= target
  3. 利用 for 循环开始右移终止指针,直至合乎终止节点到数组最初一位
  4. 应用 while 循环实现起始指针的一直右移操作,一旦符合条件记录此时长度并与已有记录值比拟,取最小值
  5. 输入长度记录值
class Solution {

    // 滑动窗口
    public int minSubArrayLen(int s, int[] nums) {
        int left = 0;
        int sum = 0;
        int result = Integer.MAX_VALUE;
        for (int right = 0; right < nums.length; right++) {sum += nums[right];
            while (sum >= s) {result = Math.min(result, right - left + 1);
                sum -= nums[left++];
            }
        }
        return result == Integer.MAX_VALUE ? 0 : result;
    }
}

注:

  • 将 result 初始值设置为 int 的最大值是为了不便前面的最小值比拟,取零的话,输入后果将会始终为零,只能取最大值。
  • sum -= nums[left++] 的执行程序为 sum – = nums[left]; left++;
  • 一层 for,一层 while,工夫复杂度不为 O(n^2^) 的起因为:对于每一个元素来说,while 循环只操作两次,而非 n 次,即 O(2*n) = O(n)
退出移动版