最大连续1的个数
1.题目
给定一个由若干 0 和 1 组成的数组 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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2.双指针解法,时间复杂度O(n)
这个是我自己的解法,因为原来做过类似的,直接就想到了这个方法,具体详情可以看我之前的博客,地址在这里。
2.1 原理
我们设置两个指针,左指针和右指针,先让右指针移动,每经过一次0,我们就让记录值k - 1,一旦k == 0 时,就代表可替换的次数用完了,right - left 就是我们要的长度,那么后续的数该怎么办呢,这时候就要轮到我们左指针了,右指针继续移动,一旦k < 0,左指针开始移动,如果左边移过去的元素是0,我们就要让k++(此时我们的范围不包括这个0,所以可替换次数要恢复),这样不管如何,我们right - left 记录的始终是最大的长度。在前面的博客中,也是利用的这个思路,主要是弄懂为什么right - left 是最大长度。
2.2 代码
int longestOnes(vector<int>& A, int K) {
int left = 0, right = 0;
int k = K;
while(right < A.size()) {
if((A[right++] == 0))
k--;
if(k < 0) {
if(A[left] == 0)
k++;
left++;
}
}
return right - left;
}
3.官方解法总思路(4,5共同的思路部分)
来源于这里。
前缀和:前缀和是一个数组的某项下标之前(包括此项元素)的所有数组元素的和。
具体关于前缀和的可以看这里。
我们可以转换一下题意,其实是让我们寻找一个包含K个0元素的最大子数组,我们将原数组的0 和 1,变成 1 和 0,这样我们就可以统计出哪个区段有多少个零元素,然后开辟一个数组存储前缀和,让右侧减去左侧的前一项,就是这个区段具有的0元素的个数。
4.二分查找法,时间复杂度O(nlogn)
4.1 原理
我们知道,我们得到的前缀和数组一定是递增的,因为数组只包含0 和 1,这样我们就可以利用二分法来找到符合我们要求的位置,我们让right从左端开始,在每一次循环中进行二分查找,查找到left的位置,然后再与最大的长度比较,决定是否取代之前的最大长度。
4.2 代码
class Solution {
public:
int longestOnes(vector<int>& A, int K) {
int n = A.size();
vector<int> P(n + 1);
for (int i = 1; i <= n; ++i) {
P[i] = P[i - 1] + (1 - A[i - 1]);
}
int ans = 0;
for (int right = 0; right < n; ++right) {
int left = lower_bound(P.begin(), P.end(), P[right + 1] - K) - P.begin();
ans = max(ans, right - left + 1);
}
return ans;
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/max-consecutive-ones-iii/solution/zui-da-lian-xu-1de-ge-shu-iii-by-leetcod-hw12/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
5.滑动窗口,时间复杂度O(n)
5.1 原理
我们知道前缀和是递增的,我们设置两个指针,左指针和右指针,先让右指针移动,我们无需再开辟数组来记录此时的前缀和值,我们只需要利用left和right两个下标再根据lsum和rsum这两个值来记录前缀和值,一旦不符合公式(根据题意推出来的公式),就让左指针开始移动,即窗口缩小,直到缩到符合要求为止,再与我们记录的最大长度去比较即可。
5.2 代码
class Solution {
public:
int longestOnes(vector<int>& A, int K) {
int n = A.size();
int left = 0, lsum = 0, rsum = 0;
int ans = 0;
for (int right = 0; right < n; ++right) {
rsum += 1 - A[right];
while (lsum < rsum - K) {
lsum += 1 - A[left];
++left;
}
ans = max(ans, right - left + 1);
}
return ans;
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/max-consecutive-ones-iii/solution/zui-da-lian-xu-1de-ge-shu-iii-by-leetcod-hw12/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

浙公网安备 33010602011771号