LeetCode1004. 最大连续1的个数 III

题目描述

给定一个由若干 0 和 1 组成的数组 A,最多可以将数组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 <= A.length <= 20000
0 <= K <= A.length
A[i] 为 0 或 1

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/max-consecutive-ones-iii

解题思路

题目翻译:

题意转换:把「最多可以把 K 个 0 变成 1,求仅包含 1 的最长子数组的长度」转换为 「找出一个最长的子数组,该子数组内最多允许有 K 个 0 」。

经过上面的题意转换,我们可知本题是求最大连续子区间,可以使用滑动窗口方法。滑动窗口的限制条件是:窗口内最多有 K 个 0。

代码思路:

1. 使用 left 和 right 两个指针,分别指向滑动窗口的左右边界;
2. right 主动右移:right 指针每次移动一步。当 A[right] 为 0,说明滑动窗口内增加了一个 0;
3. left 被动右移:判断此时窗口内 0 的个数,如果超过了 K,则 left 指针被迫右移,直至窗口内0 的个数小于等于 K为止;
4. 滑动窗口长度的最大值就是所求。

代码实现

下面是golang代码实现:

func longestOnes(A []int, K int) int {n := len(A)left, right := 0, 0                         // 左右指针,初始时都指向数组首元素res := 0                                    // 当前包含0和1的最长子数组长度zeros := 0                                  // 统计当前子数组中0的个数for right < n {                             // 右指针if A[right] == 0 {                      // right指针指向0,则0的个数加1zeros++}for zeros > K {                         // 当0的个数超过K时,可能左边边界为0,也可能右边界新增0if A[left] == 0 {                   // 当左边界指向0时,0的个数减1zeros--}left++                              // PS:不管是左边界,还是右边界遇到0,且0的个数超过K,left都需要后移}res = max(res, right - left + 1)        // 当前最长子数组数目,取res和right - left + 1中最大值right++                                 // 右边界后移}return res
}func max(a, b int) int {if a > b {return a }return b
}

运行效果:

复杂度分析

由于需要对数组遍历一次,所以时间复杂度为O(n);
借助的中间遍历为常数个,空间复杂度为O(1)。

滑动窗口类型解题模板

《挑战程序设计竞赛》这本书中把滑动窗口叫做「虫取法」,我觉得非常生动形象。因为滑动窗口的两个指针移动的过程和虫子爬动的过程非常像:前脚不动,把后脚移动过来;后脚不动,把前脚向前移动。

下面分享一个滑动窗口的模板,能解决大多数的滑动窗口问题:

func findSubArray(nums []int):N := len(nums)                                // 数组或字符串长度left, right := 0, 0                                 // 双指针,表示当前遍历的区间[left, right],闭区间sums := 0                                       // 用于统计 子数组或子区间 是否有效,根据题目可能会改成求和/计数res := 0                                             // 记录最大的满足题目要求的 子数组或子串 长度for right < N {                                 // 当右边的指针没有搜索到 数组或字符串 的结尾sums += nums[right]                  // 增加当前右边指针的数字/字符的求和/计数for 区间[left, right]不符合题意{        // 此时需要一直移动左指针,直至找到一个符合题意的区间sums -= nums[left]                  // 移动左指针前需要从counter中减少left位置字符的求和/计数left += 1                                     // 真正的移动左指针,注意不能跟上面一行代码写反// 到 for 结束时,我们找到了一个符合题意要求的 子数组/子串res = max(res, right - left + 1)         // 需要更新子数组长度的结果right += 1                                     // 移动右指针,去探索新的区间}return res

滑动窗口中用到了左右两个指针,它们移动的思路是:以右指针作为驱动,拖着左指针向前走。右指针每次只移动一步,而左指针在内部 for 循环中每次可能移动多步。右指针是主动前移,探索未知的新区域;左指针是被迫移动,负责寻找满足题意的区间。

模板的整体思想是:

1. 定义两个指针 left 和 right 分别指向区间的开头和结尾,注意是闭区间;定义 sums 用来统计该区间内的特定字符出现的次数;
2. 第一重 for 循环是为了判断 right 指针的位置是否超出了数组边界;当 right 每次到了新位置,需要加上 right 指针指向元素 的和/计数;
3. 第二重 for 循环是让 left 指针向右移动到 [left, right] 区间符合题意的位置;当 left 每次移动到了新位置,需要减去 left 指针的 指向元素/计数;
4. 在第二重 for 循环之后,成功找到了一个符合题意的 [left, right] 区间,题目要求最大的区间长度,因此更新 res 为 max(res, 当前区间的长度) 。
5. right 指针每次向右移动一步,开始探索新的区间。

模板中的 sums 需要根据题目意思具体去修改,本题是求和题目因此把sums 定义成整数用于求和;如果是计数题目,就需要改成map用于计数。当左右指针发生变化的时候,都需要更新 sums 。

另外一个需要根据题目去修改的是内层 for 循环的判断条件,即: 区间 [left, right]不符合题意的情况 。对于本题而言,就是该区间内的 0 的个数 超过了 K 。

参考链接:https://leetcode-cn.com/problems/max-consecutive-ones-iii/solution/fen-xiang-hua-dong-chuang-kou-mo-ban-mia-f76z/
来源:力扣(LeetCode)

常见面试算题题中的滑动窗口问题相关推荐

  1. 给定数组 求和等于固定值 算法_[见题拆题] 大厂面试算法真题解析 - 第一期开张...

    如今想要收获大厂offer,在面试的前几轮,总是躲不开算法这座大山. 常听人说,算法很难.这话没错.算法本身是是一个艰深的方向.但是算法题却有据可循.通过有针对性的学习和练习,我们完全可以掌握解题的基 ...

  2. ASP.NET Core中使用滑动窗口限流

    滑动窗口算法用于应对请求在时间周期中分布不均匀的情况,能够更精确的应对流量变化,比较著名的应用场景就是TCP协议的流量控制,不过今天要说的是服务限流场景中的应用. 算法原理 这里假设业务需要每秒钟限流 ...

  3. 十道经典面试算法真题详解

    前言 分享一下 腾讯常考的十道算法题(真题).在金三银四,希望对大家有帮助呀. 重排链表 最长递增子序列 环形链表 反转链表 最长回文子串 全排列 LRU 缓存 合并K个升序链表 无重复字符的最长子串 ...

  4. 后退N帧协议中的滑动窗口

    1,通俗解释: 讲到gbn,首先要讲到累积确认. 累积确认的意思是:接收方不必对收到的分组逐个发送确认,而是可以在收到几个分组后,对按序到达的最后一个分组加以确认. 比如,发送方发送0~7个帧,接收方 ...

  5. 数据结构算法——滑动窗口问题(以LeetCode滑动窗口题为例)

    1. 滑动窗口 滑动窗口算法是在给定特定窗口大小的数组或字符串上执行要求的操作,它的原理与网络传输TCP协议中的滑动窗口协议(Sliding Window Protocol)基本一致. 这种技术可以将 ...

  6. 面试难点!常用算法技巧之“滑动窗口”

    算法简介 滑动窗口,顾名思义,就是有一个大小可变的窗口,左右两端方向一致的向前滑动(右端固定,左端滑动:左端固定,右端滑动). 可以想象成队列,一端在push元素,另一端在pop元素,如下所示: 假设 ...

  7. LeetCode 滑动窗口(Sliding Window)类问题总结

    导语 滑动窗口类问题是面试当中的高频题,问题本身其实并不复杂,但是实现起来细节思考非常的多,想着想着可能因为变量变化,指针移动等等问题,导致程序反复删来改去,有思路,但是程序写不出是这类问题最大的障碍 ...

  8. 5.18 优先队列(堆) 滑动窗口(二) 交换链表的节点

    295. 数据流的中位数 最简单的思路暴力法,每次读入数据都进行排序 但是中位数只对中间的一个或两个数据感兴趣,其他数没有必要进行交换或者比较 https://leetcode-cn.com/prob ...

  9. leetcode 滑动窗口小结 (三)

    目录 978. 最长湍流子数组 题目 思路分析以及代码 1052. 爱生气的书店老板 题目 思考分析与初步代码 优化思路以及优化代码 1208. 尽可能使字符串相等 题目 思考分析以及代码 978. ...

最新文章

  1. C#多线程编程介绍——使用thread、threadpool、timer
  2. tensorflow教程 学习笔记 之 Eager execution 急切执行
  3. 倾斜摄影技术在城市规划行业中扮演着什么样的角色?
  4. 在centos安装redis
  5. 解析数据访问层操作数据库的方式
  6. java 时间换算_【时间工具】整理下java时间换算专题
  7. docker內安装TOPT
  8. 打造个人电脑安全终极防线
  9. 直线段的矢栅转换算法(DDA算法、中心画线算法、Bresenham算法)
  10. 高德地图API-获取位置信息的经纬度
  11. 2021年度总结及2022展望
  12. 关掉win10电脑hyper-v虚拟机方法
  13. 编译型语言和解释型语言的区别总结
  14. 【笔记】取模运算的用法
  15. ubuntu安装解压版mysql数据库
  16. 【机器学习应用】机器学习之无监督学习
  17. C++中Glog使用详解
  18. 实验十一 .实验十二
  19. linux rm -rf删除文件,Linux rm命令
  20. 计算机科学就是关于计算机的学问,【遇见男神】计算机科学与工程学院国奖获得者颉满刚:做人、做事、做学问...

热门文章

  1. 设计师张超越_超越响应能力–手机网站设计技巧
  2. FPGA 的基本结构(RAM/FPGA/SOC)
  3. android底层 考试 华清,Android开发架构你真的了解吗—华清创客学院
  4. 市面上有哪几种门_卧室门怎么选?市面上5种常见房门大揭秘
  5. TM7707 评估前做的功课
  6. linux安装BFE
  7. 软件平台平台物联网操作系统系列文章之-软件平台的力量
  8. 蚂蚁分类信息系统伪静态规则设置教程
  9. Linux入门和使用
  10. 【人脸识别】PCA人脸识别(识别率)【含GUI Matlab源码 802期】