文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

十五周算法训练营——滑动窗口

2024-11-30 14:35

关注
// 滑动窗口算法解题思路
1. 使用双指针技巧,初始化left=right=0,把索引左闭右开区间[left, right)称为一个窗口
2. 先不断增加right指针,扩大窗口
3. 当结果不符合要求,进行窗口收缩
4. 重复2、3步,直到终止条件

和为s的连续正数序列

输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。

序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。

示例 1:

输入:target = 9 输出:[[2,3,4],[4,5]]

// 该问题是一个滑动窗口问题
// 滑动窗口算法解题思路
// 1. 使用双指针技巧,初始化left=right=0,把索引左闭右开区间[left, right)称为一个窗口
// 2. 先不断增加right指针,扩大窗口
// 3. 当结果不符合要求,进行窗口收缩
// 4. 重复2、3步,直到终止条件
function findContinuousSequence(target) {
    const result = [];
    // 滑动窗口
    const window = [];
    let sum = 0;
    const middle = (target + 1) << 1;
    let left = 1;
    let right = 1;

    for (let i = 1; i <= middle; i++) {
        // 扩充窗口
        window.push(i);
        sum += i;
        right++;

        // 判断是否收缩窗口
        while (sum > target) {
            // 进行窗口收缩
            const temp = window.shift();
            left++;
            sum -= temp;
        }

        if (sum === target && window.length > 1) {
            result.push([...window]);
        }
    }

    return result;
}

console.log(findContinuousSequence(9));

最长不含重复字符的子字符串

请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。

示例 1:

输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。


// 可以通过滑动窗口解决
function lengthOfLongestSubstring(s) {
    // 滑动窗口
    const window = {};

    // 左右指针
    let left = 0;
    let right = 0;

    let result = 0;

    for (let i = 0; i < s.length; i++) {
        const c = s.charAt(i);

        // 扩充窗口
        window[c] = window[c] ? window[c] + 1 : 1;
        right++;

        // 判断是否收缩窗口
        while (window[c] > 1) {
            // 进行窗口收缩
            const leftC = s.charAt(left);
            window[leftC]--;
            left++;
        }

        result = Math.max(result, right - left);
    }

    return result;
}

const s = 'abcabcbb';
console.log(lengthOfLongestSubstring(s));

长度最小的子数组

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

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

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
// 滑动窗口
function minSubArrayLen(target, nums) {
    let left = 0;
    let right = 0;
    let sum = 0;
    let result = Infinity;

    while (right < nums.length) {
        // 更新状态
        sum += nums[right];
        right++;

        // 收缩窗口
        while (sum >= target) {
            result = Math.min(result, right - left);
            const presentVal = nums[left];
            // 更新状态
            sum -= presentVal;
            left++;
        }
    }

    return result === Infinity ? 0 : result;
}

无重复字符的最长子串

一、题目

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: s = "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

二、题解

function lengthOfLongestSubstring(s) {
    // 滑动窗口
    const window = {};

    // 滑动窗口的两个指针
    let left = 0;
    let right = 0;

    // 结果
    let result = 0;

    // 循环终止条件
    while (right < s.length) {
        const c = s[right];

        // 进行窗口内数据的一系列更新
        window[c] = window[c] ? window[c] + 1 : 1;

        // 移动窗口右侧
        right++;

        // 判断左侧窗口是否要收缩
        while (window[c] > 1) {
            const d = s[left];

            // 左侧窗口收缩
            left++;

            // 进行窗口内的一系列更新
            window[d]--;
        }

        // 更新答案
        result = Math.max(result, right - left);
    }

    return result;
}

const s = 'abcabcbb';

console.log(lengthOfLongestSubstring(s));

字符串排列

一、题目

给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false 。

换句话说,s1 的排列之一是 s2 的 子串 。

示例 1:

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

二、题解



function checkInclusion(s1, s2) {
    // 需要凑齐的字符
    const need = {};
    for (let i = 0; i < s1.length; i++) {
        need[s1[i]] = need[s1[i]] ? need[s1[i]] + 1 : 1;
    }

    // 滑动窗口
    const window = {};

    // 滑动窗口的两端
    let left = 0;
    let right = 0;

    // 表示窗口中满足need部分的字符数
    let valid = 0;

    while (right < s2.length) {
        const c = s2[right];

        // 进行窗口内数据的一系列更新
        if (need[c]) {
            window[c] = window[c] ? window[c] + 1 : 1;
            if (window[c] === need[c]) {
                valid++;
            }
        }

        // 移动窗口右侧
        right++;

        // 判断左侧窗口是否要收缩(当s1字符和滑动窗口字符大小相等,此时就要收缩敞口)
        while (right - left >= s1.length) {
            // 在这里判断是否找到了合法的子串
            if (valid === Object.keys(need).length) {
                return true;
            }

            const d = s2[left];
            left++;

            // 进行窗口内数据的一系列更新
            if (need[d] !== undefined) {
                if (window[d] === need[d]) {
                    valid--;
                }

                window[d]--;
            }
        }
    }

    return false;
}

const s1 = 'ab';
const s2 = 'eidbaooo';

console.log(checkInclusion(s1, s2));

滑动窗口的最大值

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回 滑动窗口中的最大值 。

示例 1:

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3 输出:[3,3,5,5,6,7] 解释: 滑动窗口的位置最大值

[1  3  -1] -3  5  3  6  7       3 1 [3  -1  -3] 5  3  6  7       3 1  3 [-1  -3  5] 3  6  7       5 1  3  -1 [-3  5  3] 6  7       5 1  3  -1  -3 [5  3  6] 7       6 1  3  -1  -3  5 [3  6  7]      7

该问题用单调队列解决(单调队列可以解决滑动窗口问题)。

// 首先建立一个单调队列的类
class MonotonicQueue {
    constructor() {
        this.queue = [];
    }

    // 在队尾添加元素n
    // 该函数在加入元素时,会将其前面比自己小的元素全部删除掉
    push(n) {
        // 将前面小于自己的元素全部删除掉
        while (this.queue.length && n > this.queue[this.queue.length - 1]) {
            this.queue.pop();
        }

        this.queue.push(n);
    }

    // 对头元素如果是n,则删除它
    pop(n) {
        if (this.queue.length > 0 && n === this.queue[0]) {
            this.queue.shift();
        }
    }

    // 返回当前队列中的最大值
    // 因为push元素时都会将比自己小的删除掉,最终结果就是一个递减的顺序,则最大值就是队列首部内容
    max() {
        return this.queue[0];
    }
}
function maxSlidingWindow(nums, k) {
    // 实例化一个单调队列
    const monotonicQueue = new MonotonicQueue();
    const result = [];

    for (let i = 0; i < nums.length; i++) {
        // 先填满整个滑动窗口的k-1个元素
        if (i < k - 1) {
            monotonicQueue.push(nums[i]);
        } else {
            // 窗口向前滑动,添加新元素
            monotonicQueue.push(nums[i]);
            // 记录当前窗口的最大值
            result.push(monotonicQueue.max());
            // 移除队列首部元素
            monotonicQueue.pop(nums[i - k + 1]);
        }
    }

    return result;
}
来源:前端点线面内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯