
题目描述
下一个数。给定一个正整数,找出与其二进制表达式中1的个数相同且大小最接近的那两个数(一个略大,一个略小)。
示例1:
输入:num = 2(或者0b10)
输出:[4, 1] 或者([0b100, 0b1])
示例2:
输入:num = 1
输出:[2, -1]
提示:
num
的范围在[1, 2147483647]之间;
- 如果找不到前一个或者后一个满足条件的正数,那么输出 -1。
解法
方法一:位运算
我们先考虑如何找出第一个比 \(num\) 大且二进制表示中 \(1\) 的个数相同的数。
我们可以从低位到高位遍历 \(num\) 的相邻两个二进制位,如果低位为 \(1\),且相邻的较高一位为 \(0\),那么我们就找到了一个位置,我们可以将这个位置的 \(0\) 变成 \(1\),将这个位置的 \(1\) 变成 \(0\)。然后我们把其余低位的 \(1\) 全部移动到最低位,这样我们就得到了一个比 \(num\) 大且二进制表示中 \(1\) 的个数相同的数。
同理,我们可以找到第一个比 \(num\) 小且二进制表示中 \(1\) 的个数相同的数。
我们可以从低位到高位遍历 \(num\) 的相邻两个二进制位,如果低位为 \(0\),且相邻的较高一位为 \(1\),那么我们就找到了一个位置,我们可以将这个位置的 \(1\) 变成 \(0\),将这个位置的 \(0\) 变成 \(1\)。然后我们把其余低位的 \(0\) 全部移动到最低位,这样我们就得到了一个比 \(num\) 小且二进制表示中 \(1\) 的个数相同的数。
在实现上,我们可以用一段代码来统一处理以上两种情况。
时间复杂度 \(O(\log n)\),其中 \(n\) 是 \(num\) 的大小。空间复杂度 \(O(1)\)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | class Solution:
def findClosedNumbers(self, num: int) -> List[int]:
ans = [-1] * 2
dirs = (0, 1, 0)
for p in range(2):
a, b = dirs[p], dirs[p + 1]
x = num
for i in range(1, 31):
if (x >> i & 1) == a and (x >> (i - 1) & 1) == b:
x ^= 1 << i
x ^= 1 << (i - 1)
j, k = 0, i - 2
while j < k:
while j < k and (x >> j & 1) == b:
j += 1
while j < k and (x >> k & 1) == a:
k -= 1
if j < k:
x ^= 1 << j
x ^= 1 << k
ans[p] = x
break
return ans
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 | class Solution {
public int[] findClosedNumbers(int num) {
int[] ans = {-1, -1};
int[] dirs = {0, 1, 0};
for (int p = 0; p < 2; ++p) {
int a = dirs[p], b = dirs[p + 1];
int x = num;
for (int i = 1; i < 31; ++i) {
if ((x >> i & 1) == a && (x >> (i - 1) & 1) == b) {
x ^= 1 << i;
x ^= 1 << (i - 1);
int j = 0, k = i - 2;
while (j < k) {
while (j < k && (x >> j & 1) == b) {
++j;
}
while (j < k && (x >> k & 1) == a) {
--k;
}
if (j < k) {
x ^= 1 << j;
x ^= 1 << k;
}
}
ans[p] = x;
break;
}
}
}
return ans;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 | class Solution {
public:
vector<int> findClosedNumbers(int num) {
vector<int> ans(2, -1);
int dirs[3] = {0, 1, 0};
for (int p = 0; p < 2; ++p) {
int a = dirs[p], b = dirs[p + 1];
int x = num;
for (int i = 1; i < 31; ++i) {
if ((x >> i & 1) == a && (x >> (i - 1) & 1) == b) {
x ^= 1 << i;
x ^= 1 << (i - 1);
int j = 0, k = i - 2;
while (j < k) {
while (j < k && (x >> j & 1) == b) {
++j;
}
while (j < k && (x >> k & 1) == a) {
--k;
}
if (j < k) {
x ^= 1 << j;
x ^= 1 << k;
}
}
ans[p] = x;
break;
}
}
}
return ans;
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 | func findClosedNumbers(num int) []int {
ans := []int{-1, -1}
dirs := [3]int{0, 1, 0}
for p := 0; p < 2; p++ {
a, b := dirs[p], dirs[p+1]
x := num
for i := 1; i < 31; i++ {
if x>>i&1 == a && x>>(i-1)&1 == b {
x ^= 1 << i
x ^= 1 << (i - 1)
j, k := 0, i-2
for j < k {
for j < k && x>>j&1 == b {
j++
}
for j < k && x>>k&1 == a {
k--
}
if j < k {
x ^= 1 << j
x ^= 1 << k
}
}
ans[p] = x
break
}
}
}
return ans
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 | function findClosedNumbers(num: number): number[] {
const ans: number[] = [-1, -1];
const dirs: number[] = [0, 1, 0];
for (let p = 0; p < 2; ++p) {
const [a, b] = [dirs[p], dirs[p + 1]];
let x = num;
for (let i = 1; i < 31; ++i) {
if (((x >> i) & 1) === a && ((x >> (i - 1)) & 1) === b) {
x ^= 1 << i;
x ^= 1 << (i - 1);
let [j, k] = [0, i - 2];
while (j < k) {
while (j < k && ((x >> j) & 1) === b) {
++j;
}
while (j < k && ((x >> k) & 1) === a) {
--k;
}
if (j < k) {
x ^= 1 << j;
x ^= 1 << k;
}
}
ans[p] = x;
break;
}
}
}
return ans;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 | class Solution {
func findClosedNumbers(_ num: Int) -> [Int] {
var ans = [-1, -1]
let dirs = [0, 1, 0]
for p in 0..<2 {
let a = dirs[p], b = dirs[p + 1]
var x = num
var found = false
for i in 1..<31 {
if ((x >> i) & 1) == a && ((x >> (i - 1)) & 1) == b {
x ^= (1 << i)
x ^= (1 << (i - 1))
var j = 0, k = i - 2
while j < k {
while j < k && ((x >> j) & 1) == b {
j += 1
}
while j < k && ((x >> k) & 1) == a {
k -= 1
}
if j < k {
x ^= (1 << j)
x ^= (1 << k)
}
}
ans[p] = x
found = true
break
}
}
if !found {
ans[p] = -1
}
}
return ans
}
}
|