Number of Times Binary String Is Prefix-Aligned 二进制字符串前缀一致的次数
问题描述:
给你一个长度为 n 、下标从 1 开始的二进制字符串,所有位最开始都是 0 。我们会按步翻转该二进制字符串的所有位(即,将 0 变为 1)。
给你一个下标从 1 开始的整数数组 flips ,其中 flips[i] 表示对应下标 i 的位将会在第 i 步翻转。
二进制字符串 前缀一致 需满足:在第 i 步之后,在 闭 区间 [1, i] 内的所有位都是 1 ,而其他位都是 0 。
返回二进制字符串在翻转过程中 【前缀一致】 的次数。
flips.length,n范围[1,50000]
分析
这个问题的模型已经有很多的变形,很早之前有个类似的开关灯的。
回到问题,数组的元素 a[i] 表示 在第i步时,将位置a[i]的元素置1,因为该问题中的下标是1开始的,所以需要做偏移。也就是对0开始的下标
a
[
i
]
−
1
a[i]-1
a[i]−1进行操作。
而且要求前缀一致,也就是整个字符串会出现前半段连续1,后半段连续0.
暴力的角度就是,在每一次的操作
a
[
i
]
−
1
a[i]-1
a[i]−1下标的元素后,检查字符串是否前缀一致。暴力的检查方式就是双指针,一个从左向右找连续1,一个从右向左找连续0,如果2指针可以相遇,即
L
+
1
=
=
R
L+1==R
L+1==R,说明符合一致。思路没问题,就是整体的时间复杂度是
O
(
n
2
)
O(n^2)
O(n2)。
但是n的规模比较大的情况下,这个时间就无法承受。
如果可以在
O
(
log
2
N
)
O(\log_{2}{N})
O(log2N)或者
O
(
1
)
O(1)
O(1)的时间复杂度下,完成验证,也可以提升速度。
验证的目标是找到连续的1,而且每次只会操作1个位置,如果记录下最远的1的位置,并且与当前操作的次数比较,就可以在$O(1)$的时间内完成验证。
或者也可以使用树状数组,每次操作更新树状数组的1个位置为1,然后验证1~cnt的前缀和 p r e s u m = = c n t presum==cnt presum==cnt。维护树状数组的时间复杂度为对数级
代码
public int numTimesAllBlue(int[] flips) {
int ans = 0,n = flips.length,idx =0;
for(int i = 0;i<n;i++){
idx = Math.max(idx,flips[i]);
if(i+1==idx) ans++;
}
return ans;
}
时间复杂度 O ( N ) O(N) O(N)
空间复杂度: O ( 1 ) O(1) O(1)
Tag
Array