Easy
题目描述
给你一个非负整数数组 nums 和一个整数 k。
如果一个数组的所有元素按位或运算的结果至少为 k,则称这个数组是 特殊的。
返回 nums 中最短的特殊非空子数组的长度,如果不存在特殊子数组,则返回 -1。
示例 1:
输入:nums = [1,2,3], k = 2
输出:1
解释:子数组 [3] 的或运算值为 3。因此,我们返回 1。
注意 [2] 也是一个特殊子数组。
示例 2:
输入:nums = [2,1,8], k = 10
输出:3
解释:子数组 [2,1,8] 的或运算值为 11。因此,我们返回 3。
示例 3:
输入:nums = [1,2], k = 0
输出:1
解释:子数组 [1] 的或运算值为 1。因此,我们返回 1。
约束条件:
1 <= nums.length <= 500 <= nums[i] <= 500 <= k < 64
解题思路
这是一道位运算和子数组的经典问题。由于数据规模较小(n ≤ 50),我们可以采用暴力枚举的方法。
解题思路:
暴力枚举所有子数组:由于约束条件较小,我们可以枚举所有可能的子数组,计算每个子数组的按位或值。
按位或运算的性质:
- 按位或运算具有单调性:
a | b >= max(a, b) - 随着子数组长度增加,按位或值只会增大或保持不变,不会减小
- 按位或运算具有单调性:
优化策略:
- 从长度为1开始枚举子数组长度
- 对于每个长度,检查所有该长度的子数组
- 一旦找到满足条件的子数组就立即返回,因为我们要找最短的
实现细节:
- 外层循环控制子数组长度(从1到n)
- 内层循环控制起始位置
- 计算当前子数组的按位或值
- 如果按位或值 >= k,返回当前长度
推荐解法:暴力枚举(在当前约束下最直接有效)
代码实现
class Solution {
public:
int minimumSubarrayLength(vector<int>& nums, int k) {
int n = nums.size();
// 枚举子数组长度
for (int len = 1; len <= n; len++) {
// 枚举起始位置
for (int i = 0; i <= n - len; i++) {
int orValue = 0;
// 计算当前子数组的按位或值
for (int j = i; j < i + len; j++) {
orValue |= nums[j];
}
// 如果满足条件,返回当前长度
if (orValue >= k) {
return len;
}
}
}
return -1;
}
};
class Solution:
def minimumSubarrayLength(self, nums: List[int], k: int) -> int:
n = len(nums)
# 枚举子数组长度
for length in range(1, n + 1):
# 枚举起始位置
for i in range(n - length + 1):
or_value = 0
# 计算当前子数组的按位或值
for j in range(i, i + length):
or_value |= nums[j]
# 如果满足条件,返回当前长度
if or_value >= k:
return length
return -1
public class Solution {
public int MinimumSubarrayLength(int[] nums, int k) {
int n = nums.Length;
// 枚举子数组长度
for (int len = 1; len <= n; len++) {
// 枚举起始位置
for (int i = 0; i <= n - len; i++) {
int orValue = 0;
// 计算当前子数组的按位或值
for (int j = i; j < i + len; j++) {
orValue |= nums[j];
}
// 如果满足条件,返回当前长度
if (orValue >= k) {
return len;
}
}
}
return -1;
}
}
/**
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
var minimumSubarrayLength = function(nums, k) {
const n = nums.length;
// 枚举子数组长度
for (let len = 1; len <= n; len++) {
// 枚举起始位置
for (let i = 0; i <= n - len; i++) {
let orValue = 0;
// 计算当前子数组的按位或值
for (let j = i; j < i + len; j++) {
orValue |= nums[j];
}
// 如果满足条件,返回当前长度
if (orValue >= k) {
return len;
}
}
}
return -1;
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(n³) | 三层嵌套循环:长度枚举O(n),起始位置枚举O(n),计算按位或O(n) |
| 空间复杂度 | O(1) | 只使用常数额外空间 |