【LetMeFly】3315.构造最小位运算数组 II:位运算
力扣题目链接:https://leetcode.cn/problems/construct-the-minimum-bitwise-array-ii/
给你一个长度为 n 的质数数组 nums 。你的任务是返回一个长度为 n 的数组 ans ,对于每个下标 i ,以下条件 均成立:
ans[i] OR (ans[i] + 1) == nums[i]
除此以外,你需要 最小化 结果数组里每一个 ans[i] 。
如果没法找到符合 条件 的 ans[i] ,那么 ans[i] = -1 。
质数 指的是一个大于 1 的自然数,且它只有 1 和自己两个因数。
示例 1:
**输入:**nums = [2,3,5,7]
输出:[-1,1,4,3]
解释:
- 对于
i = 0,不存在ans[0]满足ans[0] OR (ans[0] + 1) = 2,所以ans[0] = -1。 - 对于
i = 1,满足ans[1] OR (ans[1] + 1) = 3的最小ans[1]为1,因为1 OR (1 + 1) = 3。 - 对于
i = 2,满足ans[2] OR (ans[2] + 1) = 5的最小ans[2]为4,因为4 OR (4 + 1) = 5。 - 对于
i = 3,满足ans[3] OR (ans[3] + 1) = 7的最小ans[3]为3,因为3 OR (3 + 1) = 7。
示例 2:
**输入:**nums = [11,13,31]
输出:[9,12,15]
解释:
- 对于
i = 0,满足ans[0] OR (ans[0] + 1) = 11的最小ans[0]为9,因为9 OR (9 + 1) = 11。 - 对于
i = 1,满足ans[1] OR (ans[1] + 1) = 13的最小ans[1]为12,因为12 OR (12 + 1) = 13。 - 对于
i = 2,满足ans[2] OR (ans[2] + 1) = 31的最小ans[2]为15,因为15 OR (15 + 1) = 31。
提示:
1 <= nums.length <= 1002 <= nums[i] <= 109nums[i]是一个质数。
解题方法:位运算
解题思路
假设一个数的二进制是10111,那么最小的 a n s ans ans是多少?
想让 a n s ans ans尽可能小,就要 a n s ans ans高位尽可能小。
a n s ans ans对应的10111最高位的1有可能是0吗( a n s ans ans为0xxxx)?
不可能。
如果 a n s ans ans为
0xxxx,那么 a n s + 1 ans+1 ans+1就要为1xxxx,那么 a n s ans ans就要为01xxx,那么 a n s or ( a n s + 1 ) ans\ \text{or}\ (ans+1) ans or (ans+1)一定是11xxx不可能是10xxx。
所以 a n s ans ans一定为1xxxx。
a n s ans ans对应的10111第二高位的1有可能是0吗( a n s ans ans为100xx)?
有可能。
a n s ans ans为
10011就好。此时 a n s + 1 ans+1 ans+1为10100,它们或的结果正好是10111。
不难发现,最终结果二进制低位是连续的111,此时 a n s ans ans可以为011, a n s + 1 ans+1 ans+1为100,或起来正好是111。
a n s ans ans不能再小了,否则两个 0 0 0,怎么或也或不回都是 1 1 1了。
此外,如果 n n n是偶数,则不存在 a n s ans ans(因为 a n s ans ans或 a n s + 1 ans+1 ans+1一定为奇数),返回 − 1 -1 −1。
具体做法
讨论奇数情况:
使用一个变量 n o w = 1 now=1 now=1不断与 n n n与,结果非零就令 n n n左移一位,最终结果为 0 0 0就得到了 n n n最高位连续 1 1 1的高一位。
n n n异或(或者减去)右移一位的 n o w now now即为答案。
时空复杂度分析
- 时间复杂度 O ( l e n ( n u m s ) × log n u m s [ i ] ) O(len(nums)\times\log nums[i]) O(len(nums)×lognums[i])
- 空间复杂度 O ( 1 ) O(1) O(1),力扣返回值不计入算法空间复杂度
AC代码
C++
cpp
/*
* @LastEditTime: 2026-01-21 23:39:44
*/
/*
111
11 | 100
10111 (1+2+4+16=23)
10011 | 10100 (10011:1+2+16=19)
101
100 | 101
110
101 | 110 X
10
1 | 10 X
*/
class Solution {
private:
int get(int n) {
if (!(n & 1)) {
return -1;
}
int now = 1;
while (n & now) {
now <<= 1;
// printf("now = %d\n", now);
}
return n ^ (now >> 1);
}
public:
vector<int> minBitwiseArray(vector<int>& nums) {
vector<int> ans(nums.size());
for (int i = 0; i < nums.size(); i++) {
ans[i] = get(nums[i]); // 是nums[i]!!! 刚开始又写成i了
}
return ans;
}
};
同步发文于CSDN和我的个人博客,原创不易,转载经作者同意后请附上原文链接哦~
千篇源码题解已开源