一、题目介绍
下一个数。给定一个正整数,找出与其二进制表达式中1的个数相同且大小最接近的那两个数(一个略大,一个略小)。
示例1:
输入:num = 2
输出:[4, 1]
示例2:
输入:num = 1
输出:[2, -1]
提示:
1、num的范围在[1, 2147483647]之间;
2、如果找不到前一个或者后一个满足条件的正数,那么输出 -1。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/closed-number-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
二、解题思路
有两种理解本题的思路:
方法1
(1)求较小值:将输入的正整数转成二进制串(右边低位,左边高位),从右向左遍历找到第一个“10”,将其转成“01”,且将该位置右边所有的“1”向左移动,但不能超过“01”的位置,其余位置均置零。
(2)求较大值:将输入的正整数转成二级制串,从右向左遍历找到第一个“01”,将其转成“10”,且将该位置右边所有的“1”向右移动,其余位置均置零。
(3)注意bitset保存的二进制串,低位在前,高位在后。
方法2
(1)较小值的取值范围为 [num-1, num >> 1],记为F1。
(2)较大值的取值范围为[num+1, num << 1],记为F2。
(3)统计num转成二进制串后,1的个数为n。在F1和F2中分别找到一个与num最接近的,且1的个数也为n的数,即为结果。
三、解题代码
方法一的代码如下
class Solution {
public:
vector<int> findClosedNumbers(int num) {
bitset<32> s(num);
bitset<32> b(num);
//求略小的值
int a1 = -1;
for(int i = 1; i < 32; ++i)
{
if(s[i] == 1 && s[i-1] == 0)
{
s.flip(i-1);
s.flip(i);
for(int left = 0, right = i-2; left < right;)
{
while(left < right && s[left] == 0) left++;
while(left < right && s[right] == 1) right--;
s.flip(left);
s.flip(right);
}
a1 = (int)s.to_ulong();
break;
}
}
//求略大值
int a2 = -1;
for(int i = 1; i < 32; ++i)
{
if(b[i] == 0 && b[i-1] == 1)
{
b.flip(i);
b.flip(i-1);
for(int left = 0, right = i-2; left < right;)
{
while(left < right && b[left] == 1) left++;
while(left < right && b[right] == 0) right--;
b.flip(left);
b.flip(right);
}
a2 = (int)b.to_ulong();
break;
}
}
return {a2, a1};
}
};