#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个1
n |= 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,即18
getchar();
return 0;
}
给定一个正整数,找出一个数:与其二进制表示中1的个数相同,比该数小,而且最接近
最新推荐文章于 2022-01-02 11:23:41 发布