Kimi LeetCode 3878. 统计好子数组 Rust实现
LeetCode 3878. 统计好子数组 的 Rust 实现如下:
```rust
impl Solution {
pub fn count_good_subarrays(nums: Vec<i32>) -> i64 {
let n = nums.len();
let mut l = vec![-1i32; n];
let mut stk: Vec<usize> = Vec::new();
for i in 0..n {
let x = nums[i];
while let Some(&top) = stk.last() {
if nums[top] < x && (nums[top] | x) == x {
stk.pop();
} else {
break;
}
}
l[i] = stk.last().map(|&v| v as i32).unwrap_or(-1);
stk.push(i);
}
let mut r = vec![n as i32; n];
stk.clear();
for i in (0..n).rev() {
while let Some(&top) = stk.last() {
if (nums[top] | nums[i]) == nums[i] {
stk.pop();
} else {
break;
}
}
r[i] = stk.last().map(|&v| v as i32).unwrap_or(n as i32);
stk.push(i);
}
let mut ans: i64 = 0;
for i in 0..n {
ans += (i as i64 - l[i] as i64) * (r[i] as i64 - i as i64);
}
ans
}
}
```
思路说明
这道题的核心思路是 单调栈 + 枚举贡献:
题目定义:一个子数组是"好"的,当且仅当该子数组所有元素的 按位或(bitwise OR) 结果等于子数组中 至少出现一次 的元素。
关键观察:对于每个元素 `nums[i]`,如果它是某个子数组的按位或结果,那么该子数组中所有元素都必须是 `nums[i]` 的位运算子集,即满足 `nums[k] | nums[i] == nums[i]`。
算法步骤:
1. 找左边界 `l[i]`:从左到右遍历,用单调栈维护下标。对于 `nums[i]`,弹出所有满足 `nums[stk[-1]] < x` 且 `nums[stk[-1]] | x == x` 的元素(即被 `x` 包含的较小元素)。`l[i]` 就是栈顶元素(最后一个不满足条件的元素)。
2. 找右边界 `r[i]`:从右到左遍历,用单调栈维护下标。对于 `nums[i]`,弹出所有满足 `nums[stk[-1]] | nums[i] == nums[i]` 的元素(即被 `nums[i]` 包含的元素)。`r[i]` 就是栈顶元素(第一个不满足条件的元素)。
3. 计算贡献:以 `nums[i]` 为按位或结果的子数组数量为 `(i - l[i]) * (r[i] - i)`。
时间复杂度 `O(n)`,空间复杂度 `O(n)`。
