程序员面试金典---5.4 下一个数

本文介绍了如何使用位操作法找到一个正整数与其二进制表示中1的个数相同的相邻数。通过翻转特定位并调整,实现了找到比给定数大和小的最接近数。详细解析了如何实现这两个操作,并以13948为例进行了演示。
摘要由CSDN通过智能技术生成


题目:下一个数

给定一个正整数,找出与其二进制表达式中 1 的个数相同且大小最接近的那两个数(一个略大,一个略小)(比该数大且最接近的数 和 比该数小且最接近的数)

一、思路

1.蛮力法:
在n的二进制表示中,数出1的个数,然后增加或减小,直至找到1的个数相同的数字。
2.位操作法:取得后一个较大的数
现在给定一个数n和两个位置i和j,假设将位i从1翻转为0,位j从0翻转成1。若i>j,n就会减小;若i<j,n则会变大。
结论:

  1. 若将某个0翻转成1,就必须将某个1翻转为0。
  2. 进行位翻转时,如果0变1的位处于1变0的位的左边,这个数字就会变大。
  3. 我们想让这个数变大,但又不致太大。因此,必须翻转最右边的0,且它的右边必须有个1。
    在这里插入图片描述
    以13948为例,二进制表示如上。
    得到大于13948且最相近的数。
    步骤(1):翻转最右边、非拖尾的0
    在这里插入图片描述
    将7号位翻转后,n就会变大,为了尽量缩小数值,需要将p右方清零,把清掉的1的数量减一然后补全。
    步骤(2):将p右方的所有位清零,设拖尾0数量为c0=2,p右方0的个数c1=5, p=7
    在这里插入图片描述
    清零,需要创建一个掩码,前面是一连串的1,后面跟着p个0,做法如下。
    a= 1 << p; //除位p为1外,其余位均为0
    b = a - 1; //前面全位0,后面跟p个1
    mask = ~b; //前面全是1,后面跟p个0
    n = n & mask; // 将右边p个位清零
    简化为n &= ~((1<<p)-1)。
    步骤(3):回填c1-1个1
    在这里插入图片描述
    a = 1 << (c1 - 1); // 位c1 - 1为1,其余均为0;
    b = a - 1; // 位0到位c1-1的位为1,其余位均位0;
    n = n | b; // 在位0到位c1 - 1处插入1;
    可简化为n|= (1 << (c1 - 1)) - 1;
    3.位操作法:获取前一个较小的数
    c1是拖尾1的个数 ,c0为紧邻拖尾1的左方一连串0的个数,p为最右边、非拖尾的1
    步骤(1):初始数字,p=7,c1=2,c0=5
    在这里插入图片描述
    步骤(2)和步骤(3):将位0到位p清零
    在这里插入图片描述
    int a = 0xFFFFFFFF; //所有位置1
    int b = a << (p+1);// 位p左方的所有位为1,后跟p+1个0
    n &= b;// 将位0到位p清零
    步骤(4):在紧邻p的右方,插入c1+1个1
    在这里插入图片描述
    int a = 1 << (c1 +
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值