C++寻找下一个更大同1数算法:/pivot与>>2操作解析
问题解答:寻找比n大且二进制1的个数相同的最小数
先看你给出的代码:
int solution(int n) { int pivot = n & -n; int before = ((n ^ (n + pivot)) / pivot) >> 2; return (n + pivot) | before; }
下面拆解核心部分((n ^ (n + pivot)) / pivot) >> 2的作用,重点解释/pivot和>>2的必要性:
核心逻辑回顾
找比n大、二进制1的个数相同的最小数,本质是二进制版的「下一个排列」:
- 第一步:把n最右边的1进位(对应代码里的
n + pivot),这会让该位置的1变0,向左找到第一个0变1,中间的所有1全变0。此时得到的数比n大,但1的个数比n少(少了中间那些变成0的1)。 - 第二步:把第一步中丢失的那些1,重新放到结果的最右边低位,保证1的个数和n一致,同时数最小。
before就是用来生成这些需要补回去的1的。
逐部分解释
1. n ^ (n + pivot)
n和n+pivot的异或结果,会标记出两者所有不同的位——也就是从pivot位置(最右边的1)到进位后新1的位置之间的所有位,这些位的二进制全是1。
举个例子:n=6(二进制0110),pivot=2(0010),n+pivot=8(1000),异或结果是0110 ^ 1000 = 1110,也就是第1、2、3位全是1。
2. / pivot的作用
pivot是2^k(因为是n的最低有效置位,二进制是10...0),除以pivot等价于右移k位,把刚才的异或结果(全1序列)对齐到最低位。
还是上面的例子:1110 / 2 = 111(二进制),把原来在高位的全1序列挪到了最低位,方便后续统一处理。如果不做这一步,后续右移的位数会随pivot的位置变化而改变,无法用固定操作处理。
3. >>2的作用
刚才得到的全1序列,前两位1对应的是:
- 进位产生的新1的位置(原来的0变1,异或后为1)
pivot本身的位置(原来的1变0,异或后为1)
这两位的变化已经包含在n+pivot里了,我们需要的是剩下的1——也就是n中原本在pivot左边的连续1,这些1在n+pivot里被变成了0,需要补回到结果的最低位,才能保证1的个数和n一致。
右移2位正好可以去掉前两位无关的1,留下需要补的1序列:
- 例子n=6:
111 >> 2 = 1(二进制),把这个1补到n+pivot=8的最低位,得到1000 | 0001 = 1001(9),正确。 - 例子n=7(
0111):n+pivot=8(1000),异或结果1111,除以1得1111,>>2得11(3),最终8 | 3 = 11(1011),正确。 - 例子n=9(
1001):异或结果0011,除以1得0011,>>2得0,最终1010 | 0 = 1010(10),正确。
最终逻辑总结
(n + pivot)完成了进位操作,before生成了需要补回的最低位1序列,两者按位或就得到了比n大、二进制1的个数相同的最小数。
内容的提问来源于stack exchange,提问作者git546
相关产品推荐
相关产品推荐

