给定一个正整数,找出一个数:与其二进制表示中1的个数相同,比该数小,而且最接近

来源:互联网 发布:十字锈软件 编辑:程序博客网 时间:2024/04/29 18:07
#include <iostream>using namespace std;/*input:正整数n(32位)return:比n小,最接近n,而且二进制中1的个数与n相同(当然,0的个数也就相同了) 算法思想:从右往左找到第一个1,他的右边是0,记录下他右边1和0的个数,分别为x和y,对于返回的结果,这个1左边的位肯定不变,不用考虑,把这个1变成0,这样数字变小,同时0的个数+1,1的个数-1,为了平衡,要把他右边1的个数+1,0的个数-1,为了保证在满足数字比n小的情况下最大,1当然靠左,0靠右,也就是说,紧靠这个1的位置,是x+1个1,最右边y-1个都是0最终,原来的数字n变成:左边(32-x-y-1)位不变,0,(x+1)个1,(y-1)个0*/int getPrev(int n){int t = n;int c0 = 0;int c1 = 0;while ((t & 1) == 1){c1++;t >>= 1;}if (t == 0)//都是1,即111..111,1变0之后1少了{return -1;}while ((t & 1) == 0 && t!= 0){c0++;t >>= 1;}int p = c0 + c1;n &= ((~0) << (p + 1));//把p及其右边清0,第p位变成0,保证数字变小int mask = (1 << (c1 + 1)) - 1;//最右边c1+1个1n |= mask << (c0 - 1);//把右边这些1左移c0-1位,这样右边c0-1位为0,因为前面把一个1变成了0,所以这里要少一个0,又在小的数里面找最大的,所以1靠左边,0在右边return n;}int main(){cout << getPrev(20) << endl;//20的二进制10100变成10010,即18getchar();return 0;}

0 0