leetcode 1611
1611:使整数变为0的最少操作次数


我们需要确定在0 ≤ n ≤ 10⁹的范围内,整数n转换为二进制后最多有多少位。
二进制位数的基本概念
一个正整数n的二进制表示的位数可以通过以下公式计算:
位数=⌊log2n⌋+1
这个公式的含义是:n的二进制位数比n的二对数(向下取整)多1。这是因为:
如果n是2的幂次方(例如1, 2, 4, 8, ...),那么log₂n是整数,位数就是log₂n + 1。
如果n不是2的幂次方,那么log₂n不是整数,向下取整后加1得到位数。
计算10⁹的二进制位数
我们需要找到最大的n在范围内,即n = 10⁹。计算其二进制位数:
位数=⌊log2109⌋+1
首先计算log₂10⁹:
log2109=9×log210
我们知道:
log210≈3.321928
因此:
9×log210≈9×3.321928≈29.897352
然后取 floor:
⌊29.897352⌋=29
最后加1:
29+1=30
因此,10⁹的二进制表示有30位(数目),对应下标0...29。
while(n) {int id1 = -1, id2 = -1;for(int i = 30; i >= 0; i--) { // 从高位开始遍历,寻找 1if((1 << i) & n) {if(id1 == -1) id1 = i; // 记录较高位的 1else if(id2 == -1) id2 = i; // 记录较低位的 1else {break; // 都找到了就 break}}}
这段代码的目的是:在 n 的二进制表示中,从高位到低位,找到最高的两个 1 的位置,分别记为 id1 和 id2。
(1 << i) & n作用:判断 n 的第 i 位是否为 1。
& n:与n按位与,如果结果非零,说明n的第i位是 1。按位与就是“两个数的二进制对齐,逐位做逻辑与”,结果只有对应位同时是 1 的位置才是 1。
n^=(1<<id1);
class Solution {
public:int minimumOneBitOperations(int n) {int cnt[30]; //10⁹的二进制表示有30位(数目),对应下标0...29int res=0;for(int i=0;i<30;i++) cnt[i]=(1<<(i+1))-1; //将规律 1 的结果预处理出来存在数组 cnt[i] = 2^(i+1) - 1while(n){int id1=-1,id2=-1;for(int i=29;i>=0;i--){ //从高位开始遍历,寻找 1if((1<<i)&n){ //判断 n 的第 i 位是否为 1,按位与(包括第0位)if(id1==-1) id1=i; //记录较高位的 1else if(id2==-1) id2=i; //记录较低位的 1else{break; //都找到了就 break}}}if(id2==-1){ //只找到一个n^=(1<<id1); //第 id1 位被反转,其余位保持不变res+=cnt[id1]; //规律1}else{n^=(1<<id1);n^=(1<<id2);res+=(cnt[id1]-cnt[id2]); //规律2}}return res;}
};