贪吃蛇算法(滑动窗口算法)

1,287 阅读2分钟

看到leetcode上面一道关于滑动算法的题目。挺有意思,记录一下

1004. 最大连续1的个数 III
给定一个由若干 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。

思路:

  1. 标准的滑动窗口的题目,首先定义窗口左右侧变量(left, right),定义当前还剩余的机会数l,以及定义当前的最大长度m。
  2. 遍历数组, 判断right的值,如果为1则不消耗任何机会,窗口右侧向右移动。如果为0,要进一步判断当前的机会数,如果机会已经用完了,窗口左侧往右移动。若机会还没有用完,窗口右侧向右移动。
  3. 每次遍历的时候都需要更新一下当前最大长度,即max(m, right - left)

代码:

/**
 * @param {number[]} A
 * @param {number} K
 * @return {number}
 */
var longestOnes = function(A, K) {
    let left = 0, right = 0;
    let l = K;
    let m = 0; // 最大值
    if (A.length <= K) {
        return A.length
    }
    // 贪吃蛇算法,详情可看题解那个带佬的算法
    while (right < A.length) {
        if (A[right] === 0) {
            // 下一个是0
            if (l === 0) {
                // 没有机会了
                if (A[left] === 0) {
                    // 最左侧是0,排除了一个0,机会+1
                    l++
                }
                left++
            } else {
                // 机会还有剩余的
                l--
                right++
            }
        } else {
            // 下一个不是0,不消耗机会
            right++
        }
        m = Math.max(m, right - left)
    }
    return m
};