或与加问题

6 篇文章 0 订阅

题目:

给定 x, k ,求满足 x + y = x | y 的第 k 小的正整数 y 。 | 是二进制的或(or)运算,例如 3 | 5 = 7。

比如当 x=5,k=1时返回 2,因为5+1=6 不等于 5|1=5,而 5+2=7 等于 5 | 2 = 7。


代码:

#include <iostream>
 
using namespace std;
 
int main()
{
    long long x, k;
    cin>>x>>k;
    long long bitNum = 1;
    long long ans = 0;
    while(k)
    {
        if((x & bitNum) == 0)
        {
            ans += (bitNum * (k & 1));
            k >>= 1;
        }
        bitNum <<= 1;
    }
    cout<<ans<<endl;
    return 0;
}


思路:

应该没有更简单的解法了
-----解法说明------
x+y=x|y
这里可以推出一个结论,x&y=0。也就是说,在二进制上看,x取1的地方,y必定不能取1。从最低位考虑,若x与y在某一位上同时取1,则x+y在该位上为0,x|y在该位上为1,前面说这是最低一位x y同时取1,也就是说没有更低位加法的进位,所以这里两个结果不相等,出现了矛盾。
例子:
x = 001010
y = 110110
x + y =  1000000
x | y = 111110
偏差产生的原因是倒数第二位,x+y=0 x|y=1 且倒数第一位加法没有进位
结论: x在二进制取1的位上,y不能做出改变,只能取0
----方法----
有了上述结论,可以进一步推出只要在x取0的地方,y可以做出改变
例如
x = 10010010011
y = 00000000(0)00   k = 0
y = 00000000(1)00   k = 1
y = 0000000(1)(0)00 k = 2
y = 0000000(1)(1)00 k = 3
y = 00000(1)0(0)(0)00 k = 4
y = 00000(1)0(0)(1)00 k = 5
...
注意观察括号里的数,为x取0的比特位,而如果把括号里的数连起来看,正好等于k。
得出结论, 把k表示成二进制数,填入x取0的比特位,x取1的比特位保持为0,得到y
---代码说明---
思路有了,接着就是代码,显然用位操作是最合适的方式。
循环的思想是每次取得k的最低一位,填入到低位开始,x中比特位为0的位置上。
所以用while来判断k是否大于0,若是,说明k还未完全填完
循环体内,需要找到x当前可以填的位置,我们用bitNum来从右往左扫描x的每一位
(x & bitNum) == 0 说明x该位为0,可以把k的当前最后一位填入,用 (k & 1) 取出最后一位,用 ans += (bitNum * (k & 1)) 把k的最后一位填入到当前bitNum指向的位置。
填完后,k右移一位,去掉已经被填过的最后一位,bitNum也向左走一位,避免重复填入x的某个位置。
若x的某个位置为1,则跳过该位置,向左走一位并观察是否可以填入。
两次bitNum向左走一位,合并成一句 bitNum <<= 1;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值