Easy
题目描述
给你两个正整数 n 和 k。
你可以选择 n 的二进制表示中任意一个等于 1 的位,并将其改为 0。
返回使 n 等于 k 所需的更改次数。如果无法实现,返回 -1。
示例 1:
输入:n = 13, k = 4
输出:2
解释:
最初,n 和 k 的二进制表示分别为 n = (1101)2 和 k = (0100)2。
我们可以改变 n 的第一位和第四位。结果整数为 n = (0100)2 = k。
示例 2:
输入:n = 21, k = 21
输出:0
解释:
n 和 k 已经相等,所以不需要更改。
示例 3:
输入:n = 14, k = 13
输出:-1
解释:
无法使 n 等于 k。
约束条件:
1 <= n, k <= 10^6
提示:
- 找到
n和k的二进制表示。 - 任何在
n中等于1而在k中等于0的位都需要更改。
解题思路
这是一道位操作题目,核心思想是分析 n 和 k 的二进制表示。
分析题意:
- 我们只能将 n 中的 1 改为 0,不能将 0 改为 1
- 要使 n 等于 k,需要分析每一位的情况
关键观察:
- 如果 k 的某一位是 1,而 n 的对应位是 0,那么无法实现转换(因为我们不能把 0 改成 1)
- 如果 n 的某一位是 1,而 k 的对应位是 0,那么需要进行一次修改
- 其他情况(都是 0 或都是 1)不需要修改
解法思路:
- 首先检查是否可能:
k的每一位为 1 的地方,n的对应位也必须为 1 - 如果可能,计算需要修改的位数:
n为 1 且k为 0 的位数
位运算技巧:
- 使用
(k & n) == k检查是否可能转换 - 使用
n ^ k得到不同的位,然后与n进行 AND 操作得到需要修改的位
代码实现
class Solution {
public:
int minChanges(int n, int k) {
// 如果k中为1的位,n中对应位不是1,则无法转换
if ((k & n) != k) {
return -1;
}
// 计算需要从1改为0的位数
return __builtin_popcount(n ^ k);
}
};
class Solution:
def minChanges(self, n: int, k: int) -> int:
# 如果k中为1的位,n中对应位不是1,则无法转换
if (k & n) != k:
return -1
# 计算需要从1改为0的位数
return bin(n ^ k).count('1')
public class Solution {
public int MinChanges(int n, int k) {
// 如果k中为1的位,n中对应位不是1,则无法转换
if ((k & n) != k) {
return -1;
}
// 计算需要从1改为0的位数
int diff = n ^ k;
int count = 0;
while (diff > 0) {
count += diff & 1;
diff >>= 1;
}
return count;
}
}
var minChanges = function(n, k) {
// 如果k中为1的位,n中对应位不是1,则无法转换
if ((k & n) !== k) {
return -1;
}
// 计算需要从1改为0的位数
let diff = n ^ k;
let count = 0;
while (diff > 0) {
count += diff & 1;
diff >>= 1;
}
return count;
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(log max(n,k)) | 需要检查最多 log(max(n,k)) 位 |
| 空间复杂度 | O(1) | 只使用常数额外空间 |