【LeetCode 算法专题突破】滑动窗口(⭐)

news2024/12/25 9:45:31

文章目录

  • 前言
  • 1. 长度最小的子数组
    • 题目描述
    • 代码
  • 2. 无重复字符的最长子串
    • 题目描述
    • 代码
  • 3. 最大连续1的个数 III
    • 题目描述
    • 代码
  • 4. 将 x 减到 0 的最小操作数
    • 题目描述
    • 代码
  • 5. 水果成篮
    • 题目描述
    • 代码
  • 6. 找到字符串中所有字母异位词
    • 题目描述
    • 代码
  • 7. 串联所有单词的子串
    • 题目描述
    • 代码
  • 总结

前言

学完了双指针算法,滑动窗口那肯定是逃不掉了,我个人感觉他俩就不分家,不把滑动窗口的题目好好刷上一刷我都难受

1. 长度最小的子数组

先来一道经典的滑动窗口试试水

题目链接:209. 长度最小的子数组

题目描述


其实滑动窗口题目的解法都大同小异,我们基本上写几道题目,就能很好的掌握这个算法的思想了,来看代码:

代码

func minSubArrayLen(target int, nums []int) int {
    sum, len, n := 0, math.MaxInt32, len(nums)
    left, right := 0, 0
    for right < n {
        sum += nums[right]
        for sum >= target {
            len = min(len, right-left+1)
            sum -= nums[left]
            left++
        }
        right++
    }
    if len == math.MaxInt32 {
        return 0
    }
    return len
}

func min(a, b int) int {
    if a > b {
        return b
    }
    return a
}

我写滑动窗口的题目时,一般会按照这样一个步骤来编写代码:

  1. 使用两个指针作为窗口的左右边界
  2. 右边界往右延伸,数组内容进窗口
  3. 左边界缩小范围,判断如何出窗口

这道题目相对容易,只需要关注 sum 和 target 是否匹配就行,之后遇到类似的题目就按照这样的解题思路来求解即可。

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

还是老样子,多做题,多思考,才能多进步

题目链接:3. 无重复字符的最长子串

题目描述


这道题目其实一眼看过去,有很多解法,可以直接通过暴力解出来,也可以用滑动窗口来进行匹配,直接通过 set 去重,我之前用 C++ 做这道题的时候就是这么做的,但是在题解区学习了一下之后,我也用上了一个很巧妙而且复杂度最低的方法,来看代码:

代码

func lengthOfLongestSubstring(s string) int {
    win := [128]bool{}
    left, len := 0, 0
    for right, v := range s {
        for win[v] == true { // 出现了重复的字符,开始循环去重(代码的核心)
            win[s[left]] = false
            left++
        }
        win[v] = true
        len = max(len, right-left+1)
    }
    return len
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

这段代码可以说也是非常的清晰易懂,这个代码最核心最精华,或者说设计最巧妙的地方就是在他使用了一个 bool 类型的数组来完成去重操作,和滑动窗口的遍历完美融合到了一起。

3. 最大连续1的个数 III

让我们再来一道题目,操练一下使用滑动窗口的能力

题目链接:1004. 最大连续1的个数 III

题目描述


这道题目乍一看,会发现有很多种情况需要考虑,最重要的其实就是思考 K 个 0 该怎么翻转才能实现出最多的连续 1,来看代码:

代码

func longestOnes(nums []int, k int) int {
    left, cnt0, len := 0, 0, 0
    for right, v := range nums {
        if v == 0 {
            cnt0++
        }
        for cnt0 > k {
            if nums[left] == 0 {
                cnt0--
            }
            left++
        }
        len = max(len, right-left+1)
    }
    return len 
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

虽然题目分析起来似乎有很多中情况需要考虑,但是我们可以把问题巧妙的转化一下,从翻转 k 个 0 转化成允许 1 数组中存在 k 个 0,这样这道题目就只需要单纯的计算连续为 1 的数组,然后顺便记录一下数组中 0 的个数即可,这也是代码中的 cnt0 变量的由来~

4. 将 x 减到 0 的最小操作数

我们话不多说,继续来刷下一道题

题目链接:1658. 将 x 减到 0 的最小操作数

题目描述

在这里插入图片描述
乍一看,如果我们直接从两边找 target = x 的数感觉会很麻烦,代码也不好写,那我们该怎么做呢?来看代码:

代码

func minOperations(nums []int, x int) int {
    left, right, sum, lenth, target := 0, 0, 0, math.MaxInt32, -x
    for _, v := range nums {
        target += v
    }
    if target < 0 { // 如果全加上都达不到要求就直接返回
        return -1
    }
    for right < len(nums) { 
        sum += nums[right]
        right++
        for sum > target {
            sum -= nums[left]
            left++
        }
        if sum == target {
            lenth = min(lenth, len(nums)-(right-left))
        }
    }
    if lenth == math.MaxInt32 {
        return -1
    }
    return lenth
}

func min(a, b int) int {
    if a > b {
        return b
    }
    return a
}

我们可以将问题转化一下,把问题转化成:找出最长的中间子数组,这样我们就能求出最少需要使用的步骤了,也就能使用滑动窗口来解题了,这里我们就是把 target 设置为:数组总和 - x,这样当我们的子数组和 sum == target 的时候,就是符合题目要求的情况了
做了几道滑动窗口的题目之后,我们发现其实滑动窗口算法真正难的不是代码的编写,代码写几遍发现都是同样的写法,真正有难度的是这么样把问题转化成可以使用滑动窗口算法的形式,那怎么样才能想到呢?没有捷径,只有多练,所以我们继续下一题~

5. 水果成篮

咱们继续来练习

题目链接:904. 水果成篮

题目描述


遇到像这种题目话很多的,其实不用管,直接抓关键词就行,读完题目其实很容易就能想到这道题目该怎么做了(有了前几道题目的经验),像这道题这样不需要转换问题思路就能直接做的,其实就非常简单了,来看代码:

代码

func totalFruit(fruits []int) int {
    win := map[int]int{}
    lenth, left := 0, 0
    for right, v := range fruits {
        win[v]++
        for len(win) > 2 {
            win[fruits[left]]--
            if win[fruits[left]] == 0 {
                delete(win, fruits[left])
            }
            left++
        }
        lenth = max(lenth, right-left+1)
    }
    return lenth
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

这里我们使用的是 map 来进行对水果数量的映射,这样比较方便,其实直接用一个数组来映射也是一样的。
咱们接着练习下一道题。

6. 找到字符串中所有字母异位词

题目链接:438. 找到字符串中所有字母异位词

题目描述


来看代码:

代码

func findAnagrams(s string, p string) (ans []int) {
    lens, lenp := len(s), len(p)
    if lenp > lens { // 如果 p 比 s 长就不用找了
        return
    }

    var wins, winp [26]int
    for _, v := range p { 
        winp[v-'a']++
    }

    left, right := 0, 0
    for right < lens {
        wins[s[right]-'a']++ // 入窗口
        right++
        if wins == winp {
            ans = append(ans, left)
            wins[s[left]-'a']-- // 出窗口
            left++
        }
        if right-left+1 > lenp {
            wins[s[left]-'a']-- // 出窗口
            left++
        }
    }

    return ans
}

这道题在我的解法中,需要注意的是,在我们缩窗口的时候记得要让 wins 的字母出窗口,所以就有两个需要出窗口的地方,让 wins 的大小和 winp 始终保持一致,这样就能把所有情况都比较一遍

7. 串联所有单词的子串

刷了这么多题目,最后必须得来一道 hard 证明一下自己~

题目链接:30. 串联所有单词的子串

题目描述


来看代码:

代码

func findSubstring(s string, words []string) (ans []int) {
    if len(words) == 0 {
        return ans
    }

    slen, wlen, clen := len(s), len(words), len(words[0])
    if slen < clen*wlen {
        return ans
    }

    cmp := map[string]int{}
    for _, v := range words { // 用于比较的 cmp
        cmp[v]++
    }

    for i:= 0; i < clen; i++ {
        cnt, win := 0, map[string]int{}
        for left, right := i, i; right <= slen-clen; right+=clen {
            word := s[right:right+clen] // 截取单词 word,一个个进行匹配
            if num, _ := cmp[word]; num != 0 { // 存在 word 这个单词
                for win[word] >= num { // 如果这个 word 数量超过预期,就出窗口
                    win[s[left:left+clen]]--
                    cnt--
                    left+=clen
                }
                win[word]++ // 入窗口 + 计数
                cnt++
            } else { // 不存在 word 这个单词
                for left < right { // 比较中断了,全部 word 出窗口
                    win[s[left:left+clen]]--
                    cnt--
                    left+=clen
                }
                left+=clen // 让 left = right 重新开始(因为最后 right 会 += clen)
            }
            if cnt == wlen {
                ans = append(ans, left)
            }
        }
    }

    return ans
}

这道题目的思路和上一道题非常的像,但是代码的编写难度要高不少,我还是使用一样的思路,对每一个单词进行比较,具体的操作流程如下:

  1. 将需要比较的单词存进 cmp
  2. 因为每个单词的长度相同,所以遍历 len(words) 就能得出所有情况
  3. 接着设置 left,right 遍历整个 s
  4. 然后就开始逐个单词进行匹配,再根据计数求是否符合题目要求

总结

滑动窗口专题的一些经典题目就告一段落啦,如果什么时候对滑动窗口算法的思路亦或者是写代码的方法有疑问,就可以回来重新刷一遍,相信日后再遇到能够使用滑动窗口的题目都能游刃有余,轻松解决~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1120879.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

rust学习——引用与借用(references-and-borrowing)

引用与借用&#xff08;references-and-borrowing&#xff09; 先看一个返回参数的所有权的代码 fn main() {let s1 String::from("hello");let (s2, len) calculate_length(s1);println!("The length of {} is {}.", s2, len); }fn calculate_length(…

day01_matplotlib_demo

文章目录 折线图plot多个绘图区绘制数学函数图像散点图scatter柱状图bar直方图histogram饼图pie总结 折线图plot import matplotlib.pyplot as pltplt.figure(figsize(15, 6), dpi80) plt.plot([1, 0, 9], [4, 5, 6]) plt.show()### 展现一周天气温度情况 # 创建画布 plt.figu…

mysql高级查询

score student courses inner join 内连接&#xff1a;查询的结果为两个表匹配到的数据 1.条件&#xff1a;查询学生信息及课程对应的分数 解析&#xff1a;此时信息存储在三张表通过外键标识&#xff0c;可以先将学生和分数表根据条件连接在一起&#xff0c;然后在连接课…

升级你的照片编辑体验:Nik Collection by DxO,让你的照片更出色

如果你是一个摄影爱好者或者专业摄影师&#xff0c;你一定需要一款功能强大、易于使用的照片编辑插件套件来提升你的作品质量。今天&#xff0c;我们要向大家介绍一款备受赞誉的产品——Nik Collection by DxO。 Nik Collection by DxO是一款集合了多种照片编辑功能的插件套件…

Leetcode刷题笔记--Hot71--80

1--会议室II&#xff08;253&#xff09; 2--完全平方数&#xff08;279&#xff09; 主要思路&#xff1a; 完全背包问题&#xff0c;每一个平方数可以选取多次。 本题的物品组合与顺序无关&#xff0c;对应于组合问题&#xff0c;因此先遍历物品&#xff0c;再遍历背包。 定…

51单片机中断操作详解(03)

eg1&#xff1a;数码管如何显示出字符 51单片机40个引脚的功能需要记住** RXD&#xff1a;表示的是串行输入口INT0&#xff1a;外部中断0INT1&#xff1a;外部中断1TO : 外部中断0T1 &#xff1a;外部中断1WR: 外部输入存储器写RD: 外部输出存储器读XTK2/XTL1 单片机晶振的输…

分享5个解决msvcp140.dll丢失的方法,全面解析msvcp140.dll丢失的原因

一、MSVCP140.dll是什么&#xff1f; 首先&#xff0c;我们需要了解什么是MSVCP140.dll。MSVCP140.dll是一个动态链接库文件&#xff0c;它是Microsoft Visual C 2015 Redistributable的一部分。这个文件包含了运行使用C编写的应用程序所需的一些函数和类。因此&#xff0c;当…

从零开始,学好 Python 从大一新生自我介绍开始

从零开始&#xff0c;学好 Python 从大一新生自我介绍开始 大家好&#xff0c;我叫xxx,今年18岁&#xff0c;刚刚入学不久。我决定从零开始系统学习Python编程语言。 Python是一种解释型、交互式和脚本编程语言。它由荷兰人Guido van Rossum在1991年左右创立&#xff0c;语法简…

深入理解 C++ 右值引用和移动语义:全面解析

C11引入了右值引用&#xff0c;它也是C11最重要的新特性之一。原因在于它解决了C的一大历史遗留问题&#xff0c;即消除了很多场景下的不必要的额外开销。即使你的代码中并不直接使用右值引用&#xff0c;也可以通过标准库&#xff0c;间接地从这一特性中收益。为了更好地理解该…

023-第三代软件开发-自定义Button

第三代软件开发-自定义Button 文章目录 第三代软件开发-自定义Button项目介绍自定义Button第一类型-加声音第二类型-加样式 第三类型-减声音总结一下存在一点小问题 关键字&#xff1a; Qt、 Qml、 Button、 关键字4、 关键字5 项目介绍 欢迎来到我们的 QML & C 项目&…

无需公网IP,如何远程访问内网SVN服务?

小王以往为客户服务器做维护时&#xff0c;需要先在本地服务器上调试后再copy到客户服务器上进行发布。现在在本地搭建SVN服务器并通过花生壳发布SVN到外网&#xff0c;在客户服务器现场时也能load公司内网服务器的SVN代码。无需再次copy又发布&#xff0c;省时省力。下面来看详…

【JavaWeb】后端(MySQL+Mybatis)

目录 一、MySQL1.什么是数据库?2.MySQL安装3.MySQL连接 二、DDL1.DDL&#xff08;数据库操作)2.MySQL客户端工具3.表操作4.数据类型5.表操作 三、DML1.INSERT2.UODATE3.DELETE 四、DQL1.基本查询2.条件查询&#xff08;where&#xff09;3.分组查询&#xff08;group by&#…

Python---练习:while循环嵌套(用两次while三步走--里外各一次)

1、循环嵌套的引入 案例&#xff1a; 有天女朋友又生气了&#xff0c;惩罚&#xff1a;说3遍“老婆大人&#xff0c; 我错了”&#xff0c;这个程序是不是循环即可&#xff1f;但如果女朋友说&#xff1a;还要刷今天晚饭的碗&#xff0c;这个程序怎么书写&#xff1f; 思考&…

《红蓝攻防对抗实战》一. 隧道穿透技术详解

一.隧道穿透技术详解 从技术层面来讲&#xff0c;隧道是一种通过互联网的基础设施在网络之间传递数据的方式&#xff0c;其中包括数据封装、传输和解包在内的全过程,使用隧道传递的数据(或负载)可以使用不同协议的数据帧或包。 假设我们获取到一台内网主机的权限&#xff0c;…

概念解析 | 毫米波雷达与计算机视觉的融合

注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:毫米波雷达与计算机视觉的融合。 毫米波雷达与计算机视觉的融合 Sensors | Free Full-Text | MmWave Radar and Vision Fusion for Object Detection in Autonomous Driving: A …

分享一个MSSA插值的GRACE level数据集

1. 背景介绍 我们通常使用的GRACE数据包含球谐数据和mascon数据。而不管是球谐产品还是mascon产品&#xff0c;都存在月份数据的缺失&#xff0c;如下图所示&#xff08;Yi and Sneeuw, 2021&#xff09;。本专栏分享了一个利用多通道奇异谱分析&#xff08;MSSA&#…

一篇前段时间使用评分卡的总结_20231022

有帮助要帮我点赞哦 可以依据现在的流程&#xff0c;结合实际数据情况进行调整。 流程框架&#xff1a; eda查看字段相似性&#xff0c;提炼相似字段初步分箱必要时展开二次分箱&#xff08;或者多轮分箱调优&#xff09;可以进一步查看分箱后字段的相似性(woe值转化之后)查看…

【微信小程序】授权登录流程解析

目录 微信授权登录流程 1. 官方图示流程详解 2. 代码登录流程拆解 2.1 前端代码示例讲解 2.2 后端代码示例讲解 2.3 代码登录流程拆解 &#x1f31f; 3. 表情包存储展示&#xff08;扩展&#xff09; 附议 微信授权登录流程 1. 官方图示流程详解 ① 微信服务器验证&a…

excel单元格各种组合求和

单元格如果连续选择的话使用冒号&#xff0c;不是连续选择使用逗号&#xff1b;sum(A1:A4)表示对A1到A4求和&#xff1b;sum(A1,A4)表示求A1A4的和&#xff1b; 如下图&#xff0c;求斜线上四个单元格的和&#xff0c;结果见下图&#xff1b; 求A列和C列全部单元格的和&#x…

Python 函数:定义、调用、参数、递归和 Lambda 函数详解

函数是一段代码块&#xff0c;只有在调用时才会运行。您可以将数据&#xff08;称为参数&#xff09;传递给函数。 函数可以返回数据作为结果。 创建函数 在Python中&#xff0c;使用def关键字定义函数&#xff1a; 示例 def my_function():print("Hello from a func…