位运算入门十题

前言:刚刚接触位运算,看这个入门视频,主要是对视频内容的总结和自己思路的整理
题目由up主整理,来源于力扣官方

位运算

分为两大类

  • 逻辑位运算符

    位与 &

    位或 |

    异或 ^

    按位取反 ~

  • 位移运算符

    左移<<:x<<y x向左偏移y位,末位补0,左移可以看成x乘2

    右移>>:向右偏移y位,如果x是非负数,则高位补0,x是负数则高位补1,可以看成是x除2并向下取整

位运算的应用

表状态,用一个整数表示两种状态

各种状态之间相互独立,可以叠加

231. 2 的幂

给你一个整数 n,请你判断该整数是否是 2 的幂次方。如果是,返回 true ;否则,返回 false 。

如果存在一个整数 x 使得 n == 2x ,则认为 n 是 2 的幂次方。

思路:&

n<0,则必然不是2的幂

如果是2的幂,那么其二进制表示必为1000…(若干个0)

如:10000 - 1 = 01111,那么有n&(n-1)必然=0

return (n > 0) && (n & (n-1)) == 0;
342. 4的幂

2的偶数次幂mod 3 = 1;

2的奇数次幂mod 3 = 2

return n > 0 && (n & (n-1)) == 0 && n % 3 ==1;
191. 位1的个数

输入一个无符号整数,返回位1的个数

思路:&

遇到1就把1消去,记录消去的次数

1000 - 1 = 01111000 & 0111 = 0000 这样原来的1就被消去了

1010 - 1 = 10011010 & 1001 = 1000每进行一次&运算就会消去一个1

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int count =0;
        while(n != 0){
            n &= (n-1);
            count++;
        }
        return count;
    }
}
面试题 16.01. 交换数字

编写一个函数,不用临时变量,直接交换numbers = [a, b]ab的值。

思路:^

相同的数异或为0,任何数与0异或得它本身,满足交换律和结合律

tmp = a ^ b,这里tmp表示a和b之间的差异,ab任何与tmp进行异或都可以将另一个数还原

那么,只需要tmp和a,b中的一个,就可以还原另一个数了

这样就只需两个变量保存了

// a = a ^ b  此时a为tmp
// b = a ^ b  此时b = tmp ^ b = a
// a = a ^ b  此时a = tmp ^ a = b
136. 只出现一次的数字

思路:^

class Solution {
    public int singleNumber(int[] nums) {
        int single = 0;
        for (int num : nums) {
            single ^= num;
        }
        return single;
    }
}

异或,表达是两个数之间的差异

1 0 -> 1

0 0 -> 0

由上可看出,相同的数异或为0,任何数与0异或得它本身

461. 汉明距离

请添加图片描述

思路:^

两者进行异或,统计得到结果中1的位数

693. 交替位二进制数

给定一个正整数,检查它的二进制表示是否总是 0、1 交替出现:换句话说,就是二进制表示中相邻两位的数字永不相同。

思路:>>

判断相邻两位是否一样

这里可以用滑窗思想,固定滑窗为两位,如果窗口中的数为00,或11,则返回false

00 -> 0,11-> 3

n & 3 // 如101010 & 11 ——> 101010 & 000011 高位补0

任何数与0都为0,这样就能判断n的最后两位是不是相同的了

//情况1:最后两位为00,00 & 11 = 0 return false
//情况2:最后两位为11,11 & 11 = 3 return false
//情况3: 最后两位为01, 01 & 11 = 1
//情况4: 最后两位为10, 10 & 11 = 2

代码

public boolean hasAlternatingBits(int n) {
    while(n != 0){
        if((n & 3) == 0 || (n & 3) == 3){
            return false;
        }
        n >>= 1;
    }
    return true;
}

官方:

这个是真的绝

直接错位,两者异或

101010 >> 1 = 010101

101010 ^ 010101 = 0

class Solution {
    public boolean hasAlternatingBits(int n) {
        int a = n ^ (n >> 1);
        return (a & (a + 1)) == 0;
    }
}
1863. 找出所有子集的异或总和再求和🤒

请添加图片描述

解法不止一个,这里只讲位运算

思路:

有n个元素的数组,每一个元素都有两种状态:取或不取

那么根据状态的不同,一共会出现2ⁿ种情况,即数组有2ⁿ个子集

我们用一个n位的二进制串来表示每个元素的状态,0表示不取,1表示取

该二进制的范围为00…0 ~ 11…1,对应的十进制范围为0~(2ⁿ - 1)

2ⁿ位运算为 (1 << n)

每取一个十进制数则表示一种子集

我们把该二进制数上 出现1的所对应的元素 相互之间异或

判断第j位是否为1:i & (1 << j) > 0

得到的结果与其他子集的结果累加,返回

class Solution {
    public int subsetXORSum(int[] nums) {
        int n = nums.length;
        int ans;
        int sum = 0;
        for(int i = 0; i < (1<<n); i++){
            ans = 0;
            for(int j = 0; j < n ; j++){
                if( (i & (1 << j)) > 0){
                    ans ^= nums[j];
                }
            }
            sum += ans;
        }
        return sum;
    }
}
371. 两整数之和🤒

给你两个整数 ab不使用 运算符 +- ,计算并返回两整数之和。

思路:

^ :相同为0,不同则为1 → 不带进位的加法

题目可转化成:不带进位的加法 + 进位

&:只有两个都为1时,结果为1,其余情况都为0。这样,(a & b) << 1刚好可以表示进位

PS:这里我必须吐槽一下,这递归一下真的没想明白

递归思路整理:

  1. 首先,特殊情况(a=0|b=0)很好返回

  2. ab两者都不为0的时候

    a ^ b :不进位的加法 设为 x

    (a & b) << 1:进位 设为y

    a + b = x + y

    那么x ^ y表示 不进位的加法 + 进位 的不进位加和

    这样递归体就出来了

  3. 结束条件

    两者异或的结果一定是越来越大的,这样需要进的位也会越来越小,直到需要进的位为0

举个栗子加深一下理解:

11+10 = (11 ^ 10) + ((11 & 10) << 1) = 01 + 100

01 + 100 = (01 ^ 100) + (01 & 100)

其实这里已经可以看出两个数相加不需要进位了,直接异或得出结果

class Solution {
    public int getSum(int a, int b) {
        return b == 0 ? a : getSum(a^b, (a & b)<< 1);
    }
}

左移注意防溢出

官方的是迭代版的

面试题 05.01. 插入

请添加图片描述

即把第i~j位清0,把M塞进去

思路:

两步

  1. 清零,0与任何数都为0, ~(1<<k)

  2. 塞进去,可以用或

class Solution {
    public int insertBits(int N, int M, int i, int j) {
        int ans = N;
        for(int k = i; k <= j; k++){
            ans &= ~(1<<k);
        }
        return ans | (M<<i);
    }
}

这里感谢一下up💞,视频短小精悍,留白给我们思考,讲得也很有趣,感兴趣的朋友可以去看一看,真的很不错。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值