趣味算法:滑动窗口算法的理解与应用

这篇具有很好参考价值的文章主要介绍了趣味算法:滑动窗口算法的理解与应用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

在编程和数据结构中,滑动窗口算法是一种常见的解决问题的方法。它主要用于处理涉及连续或固定长度子数组、子序列或子字符串的问题。本文将深入探讨滑动窗口算法,包括其基本概念、应用场景、基本步骤以及具体的Java代码实践。

一、滑动窗口算法简介

滑动窗口算法是一种优化技巧,主要用于解决数组或链表中的子序列或子串问题。其主要优势是能够将一些复杂问题的时间复杂度降低至线性。

二、滑动窗口算法的应用场景

滑动窗口算法有广泛的应用场景,它通常用于解决涉及连续或固定长度子数组、子序列或子字符串的问题。以下是一些具体的例子:

  • 数组中的最大/最小子序列问题:例如,“最大连续子数组和”,“最小覆盖子串”等。这些问题通常需要找出数组或字符串中的一段连续子区间,使其满足某种条件(如和最大或最小,或者包含所有指定字符等)。

  • 固定长度的子序列问题:例如,“长度为K的无重复字符子串”,“和为K的连续子数组”等。这些问题通常需要找出长度固定或变动的子序列,满足特定的条件。

  • 计数类问题:例如,“和为K的子数组个数”,“所有字母异位词”等。这类问题需要统计满足特定条件的子数组或子字符串的数量。

滑动窗口算法的强大之处在于,它可以将这些看似复杂的问题转化为线性复杂度,大大提高了算法的运行效率。在理解了滑动窗口的基本原理后,我们可以灵活地应用它来解决各种各样的问题。

三、滑动窗口算法的基本步骤

滑动窗口算法通常涉及以下几个核心步骤:

  1. 初始化一个窗口:窗口通常表示为数组或字符串中的一段连续子区间,可以用两个指针(例如left和right)来表示其边界。初始时,这个窗口可以是空的,或者包含一个或多个元素。

  2. 移动窗口:根据具体的问题,可能需要向右移动窗口的左边界(缩小窗口),或者向右移动窗口的

右边界(扩大窗口)。窗口的移动会改变窗口中的元素。

  1. 根据窗口的变化更新结果:每次移动窗口时,都需要根据窗口中的新元素和/或去掉的元素来更新需要计算的结果。例如,如果需要计算窗口中的元素之和,当窗口增加一个元素时,需要将这个元素加到总和中;当窗口去掉一个元素时,需要将这个元素从总和中减去。

通过不断移动窗口并更新结果,我们可以在遍历一次数组或字符串后得到问题的解。

四、滑动窗口算法实践

让我们通过以下几个具体的例子,来深入理解如何在实际问题中应用滑动窗口算法。

1. 数组中的最大/最小子序列问题:最大连续子数组和

问题描述:给定一个整数数组nums,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

Java解决方案

public int maxSubArray(int[] nums) {
    int n = nums.length;
    // 初始化当前子数组的和为第一个元素的值,最大和也为第一个元素的值
    int curr_sum = nums[0], max_sum = nums[0];

    // 从第二个元素开始遍历数组
    for(int i = 1; i < n; ++i) {
        // 更新当前和,取当前元素与(当前和+当前元素)中的最大值
        curr_sum = Math.max(nums[i], curr_sum + nums[i]);
        // 更新最大和,取当前最大和与当前和中的最大值
        max_sum = Math.max(max_sum, curr_sum);
    }
    // 返回最大和
    return max_sum;
}

代码解析

上述代码中,curr_sum 是用来保存当前子数组的和,max_sum 用来保存最大的子数组和。初始化都为第一个元素。

当我们从第二个元素开始遍历数组时,对于每个元素,我们有两种选择,要么将它加入到当前的子数组中,要么开始一个新的子数组(即该元素自己成为一个新的子数组)。这取决于 curr_sum + nums[i]nums[i] 之间的大小关系,我们用 Math.max(nums[i], curr_sum + nums[i]) 来判断,选择较大者作为新的 curr_sum

同时,我们也需要更新 max_sum,也就是最大子数组和。通过 Math.max(max_sum, curr_sum) 来实现,即选择 max_sumcurr_sum 中较大者作为新的 max_sum

最后返回的 max_sum 就是最大的子数组和。

2. 固定长度的子序列问题:长度为K的无重复字符子串

问题描述:给定一个字符串 s,找出该字符串中长度为 K 的无重复字符子串的数量。

Java解决方案

public int numKLenSubstrNoRepeats(String s, int K) {
    // 计数数组,用于记录字符出现的次数
    int[] count = new int[26];
    int res = 0;
    // 双指针遍历字符串
    for (int i = 0, j = 0; j < s.length(); j++) {
        // 当前字符出现次数加1,如果这是第一次出现,则K减1
        if (count[s.charAt(j) - 'a']++ == 0) K--;
        // 如果K小于0,说明窗口太大,需要移动左指针缩小窗口
        if (K < 0 && count[s.charAt(i++) - 'a']-- == 1) K++;
        // 如果K等于0,说明找到了一个满足条件的子串,结果加1
        if (K == 0) res++;
    }
    return res;
}

代码解析

在此代码中,我们定义了一个 count 数组,用来统计各字符在滑动窗口中出现的次数。同时定义了两个指针 ij ,分别表示窗口的左右边界。

我们从左到右滑动 j 指针(即遍历字符串)。如果遍历到

的字符第一次出现,那么 K 就减一。当 K 小于0时,说明窗口太大了,有字符重复出现,需要移动左指针 i 缩小窗口,直到 K 大于等于0。在移动 i 的过程中,我们需要将离开窗口的字符的次数减一,如果这个字符的次数变为0,那么 K 就增加一。每次当 K 为0时,我们就找到了一个长度为 K 的无重复字符子串,res 就加一。

3. 计数类问题:子数组和等于K的数量

问题描述:给定一个整数数组和一个整数 k,你需要找到和为 k 的连续的子数组的个数。

Java解决方案

public int subarraySum(int[] nums, int k) {
    // 用于保存前缀和及其出现的次数
    Map<Integer, Integer> countMap = new HashMap<>();
    // 初始化前缀和为0的次数为1
    countMap.put(0, 1);

    int sum = 0, count = 0;
    // 遍历数组,计算前缀和
    for (int num : nums) {
        sum += num;
        // 如果存在一个前缀和等于当前前缀和减去k的值,那么就找到了一个和为k的子数组
        if (countMap.containsKey(sum - k)) {
            count += countMap.get(sum - k);
        }
        // 将当前前缀和添加到哈希表中,如果已经存在,则次数加1
        countMap.put(sum, countMap.getOrDefault(sum, 0) + 1);
    }
    return count;
}

代码解析

在此代码中,我们使用哈希表 countMap 来存储前缀和及其出现的次数。每次我们都计算到当前位置的前缀和 sum,然后查看哈希表中是否存在 sum - k。如果存在,那么就找到了一个子数组和为 k,结果 count 加上 sum - k 的出现次数。最后将当前的前缀和 sum 放入哈希表,更新它的出现次数。

以上就是滑动窗口算法在实际问题中的应用,通过这些实例,我们可以看出滑动窗口算法在处理这类问题时的高效性和实用性。

五、滑动窗口与其他算法的比较

滑动窗口算法是一种常用的优化策略,其与一些其他的算法在实现和使用上存在相似之处,也有其独特的优势。让我们与其他一些常用的算法进行比较。

1. 与动态规划比较

动态规划是一种用于求解最优化问题的策略,它将问题分解为多个子问题,然后根据子问题的解构造原问题的解。它保存了每个子问题的解,避免了重复计算。

滑动窗口算法与动态规划的主要区别在于,滑动窗口算法并不需要存储每个子问题的解。相反,它在原数组上“滑动”一个固定大小的窗口,通过优化计算过程,降低了空间复杂度。对于某些特定的问题,如最大/最小连续子序列问题,滑动窗口算法可能比动态规划更高效。

2. 与分治法比较

分治法是一种处理复杂问题的常用策略,它将问题分解为若干个更小、更容易处理的子问题,然后将这些子问题的解组合起来,得到原问题的解。

滑动窗口算法与分治法的一个主要区别是,滑动窗口算法并不需要将问题分解。相反,它通过移动窗口的边界来直接在原数据结构上找到解,这避免了分解问题和组合解的复杂过程。

3. 与双指针方法比较

双指针方法是一种用于处理数组或链表问题的策略,它使用两个指针在结构中前进,通常一个快一个慢,或者一个在前一个在后。

滑动窗口算法可以看作是双指针方法的一种应用,窗口的左右边界就是两个指针。但滑动窗口算法在这基础上引入了“窗口”的概念,这使得它在处理某些问题时更加直观,如需要考虑连续子序列的问题。

在使用时,滑动窗口算法、动态规划、分治法和双指针方法各有优势,需要根据具体的问题特性和数据结构来选择最合适的方法。在理解了这些算法的基本思想和优缺点后,我们就能够更加灵活地在不同的问题和场景中进行选择。

六、总结

滑动窗口是一种高效的算法优化策略,适用于解决各种需要处理连续子序列或子数组问题的场景。它的优势在于,通过将窗口在数据结构上滑动,能够以线性的复杂度解决问题,大大提升了算法的效率。

滑动窗口算法的基本步骤包括初始化窗口位置和大小,根据条件更新窗口,以及保存和更新结果。这些步骤看似简单,但在实际应用中,如何合理地调整窗口的位置和大小,以及如何精确地定义和更新结果,往往需要一些深思熟虑和实践经验。

在滑动窗口算法的实际应用过程中,我们详细探讨了处理最大/最小子序列问题、固定长度子序列问题以及计数类问题的实现方法。在实际编程中,这些问题常常以各种形式出现,理解并熟练掌握滑动窗口算法的应用,能够帮助我们更加高效地解决这类问题。

此外,我们也对滑动窗口算法与其他常见算法进行了比较,分析了各自的优点和使用场景。滑动窗口算法、动态规划、分治法和双指针方法各有特色,适合解决的问题也不尽相同。熟练掌握这些工具,并根据实际情况灵活选择,是每一位程序员必备的技能。

在学习和使用滑动窗口算法的过程中,可能会遇到各种困难和挑战。但只要我们深入理解其原理,多加实践,就一定能够克服困难,有效利用滑动窗口算法解决问题。

我希望这篇博客能够帮助你理解和掌握滑动窗口算法。如果你有任何疑问或者想要讨论的问题,欢迎在评论区留言。让我们一起学习,一起进步!文章来源地址https://www.toymoban.com/news/detail-507224.html

到了这里,关于趣味算法:滑动窗口算法的理解与应用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • LeetCode算法小抄--滑动窗口算法

    ⚠申明: 未经许可,禁止以任何形式转载,若要引用,请标注链接地址。 全文共计6244字,阅读大概需要3分钟 🌈更多学习内容, 欢迎👏关注👀文末我的个人微信公众号:不懂开发的程序猿 个人网站:https://jerry-jy.co/ 滑动窗口算法 思路 1、我们在字符串 S 中使用双指针中的

    2023年04月09日
    浏览(32)
  • 网络编程(12): TCP重传、滑动窗口、流量控制、拥塞控制

    通过序列号和确认号确保可靠传输,当发送端发送数据给接收到,接收端会返回一个确认号,表示收到消息了 超时重传 :没有在指定时间内收到 ACK 报文 超时重传的两种可能: 数据包丢失 、 确认包丢失 超时重传时间 RTO : RTO 较大:重发就变慢了,丢包之后需要半天才能重

    2024年02月12日
    浏览(44)
  • 【滑动窗口、矩阵】算法例题

    目录  三、滑动窗口 30. 长度最小的子数组 ② 31. 无重复字符的最长子串 ② 32. 串联所有单词的子串 ③ 33. 最小覆盖子串 ③ 四、矩阵 34. 有效的数独 ② 35. 螺旋矩阵 ② 36. 旋转图像 ② 37. 矩阵置零 ② 38. 生命游戏 ②  给定一个含有  n   个正整数的数组和一个正整数 

    2024年04月14日
    浏览(48)
  • 【算法优选】 滑动窗口专题——贰

    基本概念 滑动窗口是一种 基于双指针 的一种思想,两个指针指向的元素之间形成一个窗口。 分类:窗口有两类,一种是 固定大小类 的窗口,一类是 大小动态变化 的窗口。 你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fru

    2024年02月08日
    浏览(39)
  • 【算法|数组】滑动窗口

    给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度**。**如果不存在符合条件的子数组,返回 0 。 示例 1: 示例 2: 示例 3: 暴力解法 这种做法可以很容易想到,可是谁

    2024年02月12日
    浏览(30)
  • 算法专题二:滑动窗口

    长度最小的子数组 思路一: 思路二: 无重复字符的最长子串 思路一: 最大连续1的个数 开头位0 并且k为0算是一个特殊的情况这样的情况有一些考虑就走不出去前面的0而忽略到后面数组自带1,走不到这些1数据导致记录连续1的个数出问题! 将x减小到0的最小操作数 水果成篮

    2024年02月02日
    浏览(37)
  • 算法专题整理:滑动窗口

    视频课程:同向双指针 滑动窗口【基础算法精讲 01】_哔哩哔哩_bilibili 滑动窗口也可以理解为双指针法的一种。 滑动窗口的核心在于 连续 !如果需要得到的结果是 满足某种较为明显条件 的 连续 的 子数组 ,可以考虑使用滑动窗口来做。 通常情况下,滑动窗口是 枚举右端

    2024年02月12日
    浏览(36)
  • 「算法」滑动窗口

    算法需要多刷题积累经验,所以我行文重心在于分析解题思路,理论知识部分会相对简略一些 滑动窗口属于双指针,这两个指针是 同向前行 ,它们所夹的区间就称为“窗口” 啥时候用滑动窗口? 题目涉及到“子序列”、“子数组”、“子串”等概念,要你求和它们相关的

    2024年02月20日
    浏览(33)
  • 【算法系列篇】滑动窗口

    前面我们学习了什么是双指针,今天我将为大家分享一种特殊的双指针——滑动窗口,为什么说它是特殊的双指针呢?因为它也是有两个指针维护的,并且两个指针的移动方向是相同的,就跟我们平时生活中的窗口一样,两条边是往相同的方向移动的。 滑动窗口算法是一种用

    2024年02月12日
    浏览(37)
  • 【优选算法】—— 滑动窗口类问题

    本期,我给大家带来的是关于滑动窗口类算法的介绍,并通过具体的题目帮助大家思考理解。     目录 (一)基本概念 (二)题目讲解 1、难度:medium 1️⃣长度最小的子数组 2️⃣找到字符串中所有字⺟异位词 2、难度:hard 1️⃣最⼩覆盖⼦串 2️⃣串联所有单词的⼦串 总

    2024年02月02日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包