我是靠谱客的博主 矮小小蜜蜂,最近开发中收集的这篇文章主要介绍常见位运算总结及LeetCode相关题目常见的位运算相关题目参考,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章目录

  • 常见的位运算
      • 1.位操作实现乘除法
      • 2.位操作交换两个数
      • 3.位操作判断奇偶
      • 4.位操作交换符号
      • 5.位操作求绝对值
      • 6.位操作进行高低位交换
      • 7.位操作进行二进制逆序
      • 8.位操作统计二进制中1的个数
      • 9.a^ b ^b=a
  • 相关题目
      • [231. 2的幂](https://leetcode-cn.com/problems/power-of-two/)
      • [762. 二进制表示中质数个计算置位](https://leetcode-cn.com/problems/prime-number-of-set-bits-in-binary-representation/)
      • [136. 只出现一次的数字](https://leetcode-cn.com/problems/single-number/)
      • [137. 只出现一次的数字 II](https://leetcode-cn.com/problems/single-number-ii/)
      • [260. 只出现一次的数字 III](https://leetcode-cn.com/problems/single-number-iii/)
      • [476. 数字的补数](https://leetcode-cn.com/problems/number-complement/)
      • [371. 两整数之和](https://leetcode-cn.com/problems/sum-of-two-integers/)
      • [201. 数字范围按位与](https://leetcode-cn.com/problems/bitwise-and-of-numbers-range/)
      • [477. 汉明距离总和](https://leetcode-cn.com/problems/total-hamming-distance/)
      • [421. 数组中两个数的最大异或值](https://leetcode-cn.com/problems/maximum-xor-of-two-numbers-in-an-array/)
  • 参考

常见的位运算

1.位操作实现乘除法

​ 数a向右移一位,相当于将a除以2;数a向左移动一位,相当于将a乘以2。

2.位操作交换两个数

void swap(int a,int b){
a=a+b;
b=a-b;
a=a-b;
}
void swap(int a,int b){
a^=b;
b^=a;
a^=b;
}

3.位操作判断奇偶

​ 只需要将数a和1进行&(与)运算即可,如果结果是1那么说明是奇数,反之为偶数。

if(0==(a&1)){
//偶数的操作
}

4.位操作交换符号

​ 正数取反+1,正好变成其对应的负数,负数取反+1,正好变成它的原码,即正数。

int reversal(int a){
return ~a+1;
}

5.位操作求绝对值

​ 正数的绝对值就是本身,负数的绝对值是对它进行取反+1得到。首先判断正负数,然后再分别做操作。

​ 判断符号:正数右移31位得到0,负数右移31位得到-1。

int abs(int a){
int i=a>>31;
return i==0?a:(~a+1);
}
//简化一下
int abs(int a){
int i=a>>31;
return ((a^i)-i);
}

6.位操作进行高低位交换

​ 给定一个16位的无符号整数,交换高八位和低八位,给出交换后的值。注意,Java中没有无符号整数类型。

unsigned short a=34520;
a=(a>>8)|(a<<8);

7.位操作进行二进制逆序

​ 将无符号数的二进制表示进行逆序,求逆序后的结果。

unsigned short a = 34520;
a = ((a & 0xAAAA) >> 1) | ((a & 0x5555) << 1);
a = ((a & 0xCCCC) >> 2) | ((a & 0x3333) << 2);
a = ((a & 0xF0F0) >> 4) | ((a & 0x0F0F) << 4);
a = ((a & 0xFF00) >> 8) | ((a & 0x00FF) << 8);

8.位操作统计二进制中1的个数

int count(int a){
int cnt=0;
while(a){
a=a&(a-1);
cnt++;
}
return cnt;
}

​ 这个关键在于a&(a-1)这个操作,可以消除掉a最后一位的1。

9.a^ b ^b=a

相关题目

231. 2的幂

class Solution {
public boolean isPowerOfTwo(int n) {
return n>0&&(n&(n-1))==0;
}
}

762. 二进制表示中质数个计算置位

class Solution {
public int countPrimeSetBits(int L, int R) {
int ans=0;
for(int i=L;i<=R;i++){
int cnt=0,a=i;
while(a!=0){
a=a&(a-1);
cnt++;
}
if(isPrime(cnt))
ans++;
}
return ans;
}
boolean isPrime(int num){
if(num<2) return false;
if(num==3) return true;
for(int i=2;i<=Math.sqrt(num);i++){
if(num%i==0)
return false;
}
return true;
}
}

136. 只出现一次的数字

class Solution {
public int singleNumber(int[] nums) {
int xor=0;
for(int i=0;i<nums.length;i++){
xor^=nums[i];
}
return xor;
}
}

137. 只出现一次的数字 II

​ 给定一个数组,只有一个数字出现了一次,剩下的数组都是3次。

​ **第一种:**时间复杂度为 O ( n ) O(n) O(n),按位来做。

class Solution {
public int singleNumber(int[] nums) {
int ans=0;
for(int bit=0;bit<=31;bit++){
int cnt=0;
for(int i=0;i<nums.length;i++)
cnt+=(nums[i]>>bit)&1;
ans+=(cnt%3)<<bit;
}
return ans;
}
}

第二种:状态机 时间复杂度 O ( 1 ) O(1) O(1)

​ 因为数字是出现三次的,换言之对于每一个二进制位,如果出现一次的数在该二进制位为1,那么这个二进制位再在全部数字中出现的次数没有办法被3整除。

o n e s ones ones表示出现1次的数的抑或结果, t w o s twos twos表示所有出现两次数的抑或结果。

class Solution {
public int singleNumber(int[] nums) {
int ones=0,twos=0;
for(int x:nums){
ones=(ones^x)& ~twos;
twos=(twos^x)& ~ones;
}
return ones;
}
}

260. 只出现一次的数字 III

​ 这个题说的是给定一个数字,其中只有两个数出现了一次,剩下的数都出现了两次,让我们找到出现一次的两个数字。

​ 我们知道a^B^B=a,我们首先将数组中的每一个元素都进行异或,那么最终得到结果必然是两个只出现了一次的数字异或的结果,假设出现一次的数字是 x x x y y y,那么异或结果我们表示为 x o r = x xor=x xor=x^$ y$。

x o r xor xor肯定不是0,我们只需要找到 x o r xor xor中表示1的最低位是哪一位就行了,比如说 x o r = 12 xor=12 xor=12,表示成二进制就是1010,那么就可以通过从右往左数第二位上的1来区别 x x x y y y。根据该位置是不是1可以把数组分成两个部分, x x x y y y肯定在不同的两个部分中,又因为其他数字都是成对出现的,再次通过a^b^b=a可以消除掉每一部分中出现两次的数,所以两个部分剩下的结果就是 x x x y y y.

class Solution {
public int[] singleNumber(int[] nums) {
int xor=0,flag=1;
for(int x:nums){
xor^=x;
}
while((xor&flag)==0) flag<<=1;
int res[]=new int[2];
for(int x:nums){
if((flag&x)==0)
res[0]^=x;
else
res[1]^=x;
}
return res;
}
}

476. 数字的补数

class Solution {
public int findComplement(int num) {
int ans=0,move=0;
while(num!=0){
//得到num二进制的最后一位
int last=num&1;
if(last==0)
ans+=1<<move;
//移动位数+1
move++;
//num的最后一位已经判断过,不需要再使用了,所以无符号右移一位
num>>>=1;
}
return ans;
}
}

371. 两整数之和

​ 注意运算符的优先级:先算术运算,后移位运算,最后位运算。b=(a&b)<<1;需要加括号,否则会先进行移位操作然后再位操作,这样得到的结果是错误的。

/*
以a=5,b=7为例,a和b的二进制分别是101、111.
- 1.a + b 的问题拆分为 (a 和 b 的无进位结果) + (a 和 b 的进位结果),一般来说无进位的加法可以用异或实现
有进位的加法可以通过&运算实现。对于5+7来说,就是无进位结果2和进位结果10相加。
- 2.无进位加法使用异或运算计算得出:a^b
- 3.进位结果使用与运算和移位运算计算得出:a&b<1
- 4.循环此过程,直到进位结果为 0
*/
class Solution {
public int getSum(int a, int b) {
while(b!=0){
//无进位的加 tmp=101^111=010,也就是2.
int tmp=a^b;
//a&b=101&111=101 左移一位得到1010,也就是10 
b=(a&b)<<1;
a=tmp;
}
return a;
}
}

201. 数字范围按位与

考虑范围[m, n],如果n比m二进制位数高的话,在累计按位与的过程中,数字的每一个二进制位数必然都出现过0,所以一旦出现位数不同的情况,结果必然为0。

程序中,m, n在向右移位的过程中,如果m, n相等了,就说明累计按位与的左边肯定等于m, n此时的状态,这时候就可以向左移回来了,相当于右边所有位数都补0,相等的部分照旧。

如果m, n位数不相等,肯定会移到底,两者都为0时才会相等停止循环,这时候再向左移多少结果都是0。

class Solution {
public int rangeBitwiseAnd(int m, int n) {
int ans = 0;
while(m!=n){
m>>=1;
n>>=1;
ans+=1;
}
return n << ans;
}
}

477. 汉明距离总和

​ 2个数比较二进制对应位不同,就是比较每一位的情况然后把各个位上的情况相加组成最后的答案。假设 n u m s nums nums数组一共有4个数,这四个数的每一位不是0就是1,先看最低位,假设这四个数的最低位分别是:1 0 1 0。显而易见,0有两个个,1也有两个,从四个数中任意挑选2个数,我们先只比较这两个数最低位不同的情况,从四个数里面任意挑选两个有6种情况,但实际上最后一位不同的情况只有4种,为啥呢,从最低位为1的数里挑一个有两种情况,从最低位为0的数里挑一个也有两种情况, 2 ∗ 2 = 4 2*2=4 22=4,所以最低位不同的情况有4种,以此类推算得每一位不同的情况进行累加就是答案。

​ 所以这个题实际上与0的个数和1的个数有关系。

class Solution {
public int totalHammingDistance(int[] nums) {
int res=0;
//10^9是31位,所以循环位数是31位
for(int i=0;i<=30;i++){
int ones=0;
for(int x:nums)
if((x>>i&1)==1)
ones++;
//1的个数*0的个数
res+=ones*(nums.length-ones);
}
return res;
}
}

421. 数组中两个数的最大异或值

public class Solution {
public int findMaximumXOR(int[] nums) {
int res = 0;
int mask = 0;
for (int i = 30; i >= 0; i--) {
mask = mask | (1 << i);
Set<Integer> set = new HashSet<>();
for (int num : nums) {
set.add(num & mask);
}
int temp = res | (1 << i);
for (Integer prefix : set) {
if (set.contains(prefix ^ temp)) {
res = temp;
break;
}
}
}
return res;
}
}

参考

位运算有什么奇技淫巧?

最后

以上就是矮小小蜜蜂为你收集整理的常见位运算总结及LeetCode相关题目常见的位运算相关题目参考的全部内容,希望文章能够帮你解决常见位运算总结及LeetCode相关题目常见的位运算相关题目参考所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(52)

评论列表共有 0 条评论

立即
投稿
返回
顶部