Skip to content

Commit 05ced95

Browse files
author
lucifer
committed
feat: $1004
1 parent 42d30ae commit 05ced95

File tree

3 files changed

+134
-0
lines changed

3 files changed

+134
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ leetcode 题解,记录自己的 leetcode 解题之路。
345345
- [0959. 由斜杠划分区域](./problems/959.regions-cut-by-slashes.md) 🆕
346346
- [0978. 最长湍流子数组](./problems/978.longest-turbulent-subarray.md)
347347
- [0987. 二叉树的垂序遍历](./problems/987.vertical-order-traversal-of-a-binary-tree.md) 91
348+
- [1004. 最大连续 1 的个数 III](./problems/1004.max-consecutive-ones-iii.md) 🆕
348349
- [1011. 在 D 天内送达包裹的能力](./problems/1011.capacity-to-ship-packages-within-d-days.md)
349350
- [1014. 最佳观光组合](./problems/1014.best-sightseeing-pair.md)
350351
- [1015. 可被 K 整除的最小整数](./problems/1015.smallest-integer-divisible-by-k.md)

SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@
205205
- [0959. 由斜杠划分区域](./problems/959.regions-cut-by-slashes.md) 🆕
206206
- [0978. 最长湍流子数组](./problems/978.longest-turbulent-subarray.md)
207207
- [0987. 二叉树的垂序遍历](./problems/987.vertical-order-traversal-of-a-binary-tree.md) 91
208+
- [1004. 最大连续 1 的个数 III](./problems/1004.max-consecutive-ones-iii.md) 🆕
208209
- [1011. 在 D 天内送达包裹的能力](./problems/1011.capacity-to-ship-packages-within-d-days.md)
209210
- [1014. 最佳观光组合](./problems/1014.best-sightseeing-pair.md)
210211
- [1015. 可被 K 整除的最小整数](./problems/1015.smallest-integer-divisible-by-k.md)
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
## 题目地址(1004. 最大连续 1 的个数 III)
2+
3+
https://leetcode-cn.com/problems/max-consecutive-ones-iii/
4+
5+
## 题目描述
6+
7+
```
8+
给定一个由若干 0 和 1 组成的数组 A,我们最多可以将 K 个值从 0 变成 1 。
9+
10+
返回仅包含 1 的最长(连续)子数组的长度。
11+
12+
 
13+
14+
示例 1:
15+
16+
输入:A = [1,1,1,0,0,0,1,1,1,1,0], K = 2
17+
输出:6
18+
解释:
19+
[1,1,1,0,0,1,1,1,1,1,1]
20+
粗体数字从 0 翻转到 1,最长的子数组长度为 6。
21+
22+
示例 2:
23+
24+
输入:A = [0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1], K = 3
25+
输出:10
26+
解释:
27+
[0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1]
28+
粗体数字从 0 翻转到 1,最长的子数组长度为 10。
29+
30+
 
31+
32+
提示:
33+
34+
1 <= A.length <= 20000
35+
0 <= K <= A.length
36+
A[i] 为 0 或 1 
37+
```
38+
39+
## 前置知识
40+
41+
-
42+
43+
## 公司
44+
45+
- 暂无
46+
47+
## 思路
48+
49+
这道题我在 [字节跳动的算法面试题是什么难度?](https://lucifer.ren/blog/2020/09/06/byte-dance-algo-ex/) 提到过这道题的换皮题。大家可以将这两道题目结合起来理解。接下来,我们看下这道题如何解决。
50+
51+
如果题目没有`最多可以将 K 个值从 0 变成 1` 。这个条件,那么会很简单,是一个常规的滑动窗口模板题。 我们加上这个条件对问题有什么样的影响呢?
52+
53+
这道题我们只需要记录下加入窗口的是 0 还是 1:
54+
55+
- 如果是 1,我们什么都不用做
56+
- 如果是 0,我们将 K 减 1
57+
58+
相应地,我们需要记录移除窗口的是 0 还是 1:
59+
60+
- 如果是 1,我们什么都不做
61+
- 如果是 0,说明加进来的时候就是 1,加进来的时候我们 K 减去了 1,这个时候我们再加 1。
62+
63+
### 为什么这种思路可行?
64+
65+
这其实就是滑动窗口的常见套路。 这种算法可行的根本原因在于其本身就是暴力枚举的优化。如果让你用最暴力的解法如何求解呢?无非就是枚举所有的子数组,这需要 $O(N^2)$ 的时间复杂度,接下来判断子数组是否满足**最多将 k 个 0 变成 1,子数组全部为 1**。如果满足则更新答案即可。 如何对暴力解进行优化呢?
66+
67+
比如现在是判断的子数组 A[2:3],我们计算出 A[2:3] 有一个 0,也就是说需要将一个 0 变成 1 才行。那么当我们继续判断子数组 A[2:4],我们只需要判断 A[4],同时结合 A[2:3]的计数信息即可。**滑动窗口就是专门优化这种每次只在端点变化,中间都不变,从而省去了中间即重复计算,进而将窗口内的计数信息从 O(w) 降低到 O(1)**,其中 w 为窗口大小。
68+
69+
接下来,我们继续优化。实际上也是没有必要两层循环枚举所有子数组的。而是在 $O(n)$ 的时间就可以枚举所有的合法子数组。为什么呢?你可以换个角度思考:
70+
71+
所有的子数组就是
72+
73+
- 以索引 0 为右端点的所有子数组
74+
- - 以索引 1 为右端点的所有子数组
75+
- - 以索引 2 为右端点的所有子数组
76+
- ...
77+
- - 以索引 n - 1 为右端点的所有子数组,其中 n 为数组长度
78+
79+
这样的话我们就可以使用双指针技巧。右指针模拟右端点,使用左指针模拟左端点了。**如果以索引 i 为右端点的子数组 0 的个数不大于 k,那么左指针 l 没必要右移,因为当前右指针 r 和所有的索引 i, 其中 l <= i <= r 的组合 0 的个数都不会大于 k,而且子数组还更短了,不可能是答案,因此我们直接右移右指针,这是算法的关键**。通过这种方式算法的时间复杂度可从 $O(n^2)$ 降低到 $n$。
80+
81+
## 代码
82+
83+
- 语言支持:Python3
84+
85+
Python3 Code:
86+
87+
```py
88+
class Solution:
89+
def longestOnes(self, A: List[int], K: int) -> int:
90+
i = ans = 0
91+
92+
for j in range(len(A)):
93+
K -= A[j] == 0
94+
while K < 0:
95+
K += A[i] == 0
96+
i += 1
97+
ans = max(ans, j - i + 1)
98+
return ans
99+
100+
```
101+
102+
甚至更简洁:
103+
104+
```py
105+
class Solution:
106+
def longestOnes(self, A: List[int], K: int) -> int:
107+
i = 0
108+
109+
for j in range(len(A)):
110+
K -= 1 - A[j]
111+
if K < 0:
112+
K += 1 - A[i]
113+
i += 1
114+
return j - i + 1
115+
```
116+
117+
**复杂度分析**
118+
119+
令 n 为数组长度。
120+
121+
- 时间复杂度:$O(n)$
122+
- 空间复杂度:$O(1)$
123+
124+
> 此题解由 [力扣刷题插件](https://leetcode-pp.github.io/leetcode-cheat/?tab=solution-template) 自动生成。
125+
126+
力扣的小伙伴可以[关注我](https://leetcode-cn.com/u/fe-lucifer/),这样就会第一时间收到我的动态啦~
127+
128+
以上就是本文的全部内容了。大家对此有何看法,欢迎给我留言,我有时间都会一一查看回答。更多算法套路可以访问我的 LeetCode 题解仓库:https://github.com/azl397985856/leetcode 。 目前已经 40K star 啦。大家也可以关注我的公众号《力扣加加》带你啃下算法这块硬骨头。
129+
130+
关注公众号力扣加加,努力用清晰直白的语言还原解题思路,并且有大量图解,手把手教你识别套路,高效刷题。
131+
132+
![](https://tva1.sinaimg.cn/large/007S8ZIlly1gfcuzagjalj30p00dwabs.jpg)

0 commit comments

Comments
 (0)