写这篇文章是因为最近在刷LeetCode的算法题但是每次,都没有得心应手的解决方法和思路,每次都要看解答.觉得需要把刷过的题做个总结.位运算在计算机的运行计算速度是相当的快的
基础知识:
- &与运算:两个都为true(1),结果才是true(1)
- |或运算:两个中一个为false(0),结果就是false(0)
- ~取反运算:true取反 成false, false 取反为true.
- ^异或运算:相同的为0(想象成两个男的或者两个女的在一起)显然是不允许的,所以为false.
异或运算:
A = 001010
B = 101100
A ^ B = 100110
- 左移和右移:
- 左移:A<<B,将A的二进制表示的每一位向左移B位,左边超出的位截掉,右边不足的位补0
- 右移:也是能很快实现除法运算N >> n即表示右移n位,相当于除以2的n幂
- 有符号右移(算数右移):空缺的数补齐符号位的数
- 无符号右移(逻辑右移):不管符号位是什么前面补0
下面是一些LeetCode遇到的一些问题:
LeetCode136. 只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
由基础知识4可知,一个数异或一个数偶数次,还是他本身,题中只有一个元素出现一次,而其他的都出现的了两次.刚好可以利用异或运算的性质来解决.
class Solution {
public int singleNumber(int[] nums) {
int ans = 0;
for(int num: nums) {
ans ^= num;
}
return ans;
}
}
LeetCode191. 位1的个数
有图可知,n-1会将n的从右向左第一个不是0的数变成0,且后面的数变成1,由基础知识1可知,与运算(n&n-1)会将变化的数都归为0.我们只需要设置一个变量表示一共有多少的1经过了此上述过程即可.
public class Solution {
public int hammingWeight(int n) {
int count =0;
while(n!=0){
count++;
n = n&(n-1);
}
return count;
}
}
LeetCode231. 2的幂
给定一个整数,编写一个函数来判断它是否是 2 的幂次方。
方法一:
我们可以发现2的幂在二进制中只有一个1,所以可以把问题转化为求二进制数中1的个数.
class Solution {
//2的幂次方中,二进制只有一位是1
public boolean isPowerOfTwo(int n) {
//考虑特殊情况
if(n<0 ){return false;}
int count =0;
while(n!= 0){
count++;
n &= n-1;
}
return count ==1;
}
}
方法二:
和上面方法差不多,n如果为2的幂,那么n-1这个数只有一位是0其他都是1,可以用与运算,看是否为0;
- n 二进制最高位为 1,其余所有位为 0;
- n−1 二进制最高位为 0,其余所有位为 1;
- 一定满足 n > 0。
class Solution {
public boolean isPowerOfTwo(int n) {
return n > 0 && (n & (n - 1)) == 0;
}
}
LeetCode371. 两整数之和
不使用运算符 + 和 - ,计算两整数 a 、b 之和。
- 在位运算操作中,异或的一个重要特性是无进位加法(基础4)。
- 所以利用与运算和异或即可解答
- a + b 的问题拆分为 (a 和 b 的无进位结果) + (a 和 b 的进位结果)
- 无进位加法使用异或运算计算得出
- 进位结果使用与运算和移位运算计算得出
- 循环此过程,直到进位为 0
class Solution {
public int getSum(int a, int b) {
int sum =a;
while(b !=0){
sum =a^b;
b =(a & b)<< 1;
a =sum;
}
return sum;
}
}
结语:
就先写这么多以后刷到别的再添加,如果大家觉得有帮助的,点赞支持下啦~,或者有建议的可以评论。非科班自学学习不易。