通过位操作将数字加1
位操作使用按位运算符(如 AND(&)、OR(|)、NOT(~)、XOR(^)、左移(<<) 和右移(>>))对位流进行逻辑运算以获得所需结果。使用按位运算符是有益的,因为我们可以操作单个位,并且它们比其他运算符更快。
问题陈述
给定一个数字。仅使用按位运算符将数字加1。(不要使用像 ‘+’、‘-’、‘*’ 或 ‘/’ 这样的算术运算符)
方法一:使用反码/非运算符
按位补码/反码是使用 NOT(~) 运算符实现的。
对于数字 n,n 的按位补码,即 ~n = -(n+1)。因此,我们可以通过仅取 ~n 的值并忽略符号来得到 n+1。这可以使用 abs() 函数来完成,该函数返回变量的值并忽略符号。
伪代码
procedure inc (num) num = |~n| // | | represents the abs() function end procedure
示例
在下面的程序中,我们通过使用按位补码运算符和绝对值函数来计算数字加1的结果。
#include <bits/stdc++.h>
using namespace std;
// Function for finding the increment of input by 1
int inc(int num){
// using the abs() function to get the value obtained by applying the ~ operator
num = abs(~num);
return num;
}
int main(){
int input = 7;
cout << input << " + 1 using bit manipulation = " << inc(input);
return 0;
}
输出
7 + 1 using bit manipulation = 8
时间复杂度 − O(1),因为没有实现循环。
空间复杂度 − O(1),因为没有使用额外的空间。
方法二
来看一些二进制加法的例子,如下所示:

从上面的例子可以看出,在对1进行二进制加法时,数字右边第一个未设置位的左边二进制位保持不变。但是,右边第一个未设置位被设置,右边所有的位都被反转,即设置位被取消设置,未设置位被设置(0 转换为 1,1 转换为 0)。
因此,我们可以将我们的问题分解成两个基本部分:
设置右边第一个未设置位。
反转右边所有的位。
递归方法伪代码
procedure inc (num)
if num & 1 == 0
ans = num | 1
else
ans = inc (num >> 1) << 1
end if
end procedure
示例
在下面的程序中,我们使用递归根据上面解释的思想将数字加1。
#include <bits/stdc++.h>
using namespace std;
// Function for finding the increment of input
int inc(int num){
// check if the LSB is set or not. If it is unset, it enters if otherwise, it goes to else
if ((num & 1) == 0) {
// LSB is set
return num | 1;
}
else {
// The number is right shifted and the function is called again
// After obtaining the return number from called function, the number is left shifted
return inc(num >> 1) << 1;
}
}
int main(){
int input = 14;
cout << input << " + 1 using bit manipulation = " << inc(input);
return 0;
}
输出
14 + 1 using bit manipulation = 15
时间复杂度 − O(k),其中 k 是从右边第一个未设置位的位数。
空间复杂度 − O(k),由于递归堆栈空间。
迭代方法伪代码
procedure inc (num)
m = 1
while num & m
num = num & (~m)
m = m << 1
end while
num = num | m
end procedure
示例
在下面的程序中,我们使用一个掩码数字,该数字在每次迭代中都会更改,直到我们得到右边第一个未设置位。发现它后,将设置未设置位,并将右边所有其他位反转。
#include <bits/stdc++.h>
using namespace std;
// Function for finding the increment of input
int inc(int num){
// declare a mask with value 1 which is used to find the first unset bit from right side
int m = 1;
// checks if LSB is set. If set enter the loop and repeat till we get to the unset bit
while (num & m) {
num &= ~m;
// mask is changed at every iteration to set the unset bit and toggle bits when the loop ends
m <<= 1;
}
// mask used to set the unset bit and toggle all the bits on the right-hand side
num |= m;
return num;
}
int main(){
int input = 14;
cout << input << " + 1 using bit manipulation = " << inc(input);
return 0;
}
输出
14 + 1 using bit manipulation = 15
时间复杂度 − O(k),其中 k 是从右边第一个未设置位的位数。
空间复杂度 − O(1)
方法三
在这种方法中,我们试图通过减少查找第一个未设置位的时间来降低时间复杂度。在这种方法中,我们将首先找到从右边第一个未设置位,设置它并反转右边所有的位。
伪代码
procedure inc (num)
pos = log2 (num & ~num)
add = 1 << pos
num = num | add
if pos != 0
toggle = (1 << pos) - 1
num = num ^ toggle
end if
ans = num
end procedure
示例
在下面的程序中,使用 Log2() 操作来查找未设置位,左移和 OR 来设置位,以及左移和 XOR 来反转位。
#include <bits/stdc++.h>
using namespace std;
// Function for finding the increment of input
int inc(int num){
// finds the position of the first unset bit from right
int pos = log2(num & ~num);
// the following 2 operations combined set the unset bit
int add = 1 << pos;
num |= add;
// Toggling bits only for the numbers where the first unset bit was not the LSB
if (pos != 0){
// Using left shift and XOR operations to toggle bits
int toggle = (1 << pos) - 1;
num ^= toggle;
}
return num;
}
int main(){
int input = 14;
cout << input << " + 1 using bit manipulation = " << inc(input);
return 0;
}
输出
14 + 1 using bit manipulation = 15
时间复杂度 − O(1)
空间复杂度 − O(1)
结论
总之,为了将数字加1,我们可以使用反码概念,或者通过分析加1时位的性质,我们可以遵循上述方法来获得所需的结果。
数据结构
网络
关系数据库管理系统 (RDBMS)
操作系统
Java
iOS
HTML
CSS
Android
Python
C语言编程
C++
C#
MongoDB
MySQL
Javascript
PHP