我们假设
P
[
i
]
P[i]
P[i]代表
[
0
,
i
]
[0,i]
[0,i]中
1
1
1的个数的前缀和。
那么
P
[
r
i
g
h
t
]
−
P
[
l
e
f
t
−
1
]
P[right]-P[left-1]
P[right]−P[left−1]代表区间
[
l
e
f
t
,
r
i
g
h
t
]
[left,right]
[left,right]中的
1
1
1的个数的,我们就是要找到满足
P
[
l
e
f
t
]
−
P
[
l
e
f
t
−
1
]
<
=
k
P[left]-P[left-1]<=k
P[left]−P[left−1]<=k的最大的
r
i
g
h
t
−
l
e
f
t
+
1
right-left+1
right−left+1的长度,
怎么找到这个left?二分查找,时间复杂度
O
(
n
l
o
g
(
n
)
)
O(nlog(n))
O(nlog(n))
这个时候我么遍历
r
i
g
h
t
right
right,为什么遍历
r
i
g
h
t
right
right?因为下面的c++中有
l
o
w
e
r
_
b
o
u
n
d
(
)
lower\_bound()
lower_bound()这个函数可以方便的使用,找到满足条件的最小的
l
e
f
t
left
left就好了。
也就是
P
[
l
e
f
t
−
1
]
>
=
P
[
r
i
g
h
t
]
−
k
P[left-1]>=P[right]-k
P[left−1]>=P[right]−k,我们可以使用
l
o
w
e
r
_
b
o
u
n
d
(
)
lower\_bound()
lower_bound()函数方便的找到最小的left
为了不处理边界条件,我们将
P
[
]
P[]
P[]数组整个向右移动
1
1
1,这样
P
[
i
]
P[i]
P[i]就代表
[
0
,
i
−
1
]
[0,i-1]
[0,i−1]中
1
1
1的个数。
于是我们有了下面的代码
滑动窗口,时间复杂度
O
(
n
)
O(n)
O(n)
代码很短,如代码所示
二分代码
class Solution {
public:
int longestOnes(vector<int>& A, int K) {
int n=A.size();
vector<int>P(n+2);
for(int i=1;i<=n;i++){
P[i]=P[i-1]+(1-A[i-1]);
}
int res=-1;
for(int i=n-1;i>=0;i--){
int left=lower_bound(P.begin(),P.end(),P[i+1]-K)-P.begin();
res=max(res,i-left+1);
}
printf("%d\n",res);
return res;
}
};
滑动窗口代码
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;
}
};