位运算(关于leetCode上面一些简单位运算题目的总结)

本文总结了LeetCode上四道与位运算相关的题目,包括找寻丢失的数字、只出现一次的数字、颠倒二进制位和计算二进制中1的个数。通过异或操作和位移来解决这些问题,详细解析了解题思路和代码实现,并讨论了n&(n-1)操作在位运算中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目一:找寻丢失的数字

题目描述:给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。

解法思路:先将0-nums.length中的数都异或一遍得到一个结果,再拿这个结果去nums中异或,因为这个两个循环中,没有丢失的数字都是出现了两次的,而丢失的那个数只出现了一次,这样相同为0  不同为1的异或运算到最后只剩下那个丢失的数字

代码实现:

public int missingNumber(int[] nums) {
        //得到数组的长度
        int n = nums.length;
        //记录结果
        int result = 0;
        //先将数组长度范围内的每个数进行异或运算,得到一个结果
        for(int i = 0;i <= n;i++){
            result ^= i;
        }
        //拿result的结果跟nums中的每一个数进行异或运算,异或出的结果就是nums中缺少,而在n范围内多于的那个数
        for(int i = 0;i < nums.length;i++){
            result ^= nums[i];
        }
        return result;
}

题目二:只出现一次的数字

题目描述:给你一个非空整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

思路:同样的异或运算,和上一道题类似,当每个数都是成对出现的,而多于的那个单独出现的数,一进行异或运算,就可以查找出来了

代码实现:

public int singleNumber(int[] nums){
        if(nums.length < 2){
            return nums[0];
        }
        //相同为0  不同为1  0异或任何数都等于这个数
        int result = nums[0];
        for(int i = 1;i <nums.length;i++){
            result = nums[i] ^ result;
        }
        return result;
}

题目三:颠倒二进制位

题目描述:颠倒给定的 32 位无符号整数的二进制位n

思路:根据题目,给定的是32位的二进制数,所以只需要j将n循环32次,每次得到二进制数n的最后一位,然后用一个32位的变量,每次向左移动一位,腾出位置,来加上每一次得到的最后一位数,n再右移,去除最后一位数。最后的结果就是颠倒过来的二进制位

代码实现:代码给出了原始版和优化版本

//原始版
public int reverseBits(int n){
        int result = 0;
        //题目给定是32位 所以只需要循环32次
        for(int i = 0;i < 32;i++){
            //每一次得到n的最后一位数  (只需要&1即可) 与运算:两个数都是1才会返回1  否则返回0
            int lastBit = n & 1;
            //将result左移一位腾出位置并将lastBit 添加到result上面
            result = (result << 1) + lastBit;
            //将n右移一位 继续获得最后一位二进制数
            n = n >> 1;
        }
        return result;
    }


    //优化:在result加值的过程中 可以直接采用或的形式  因为得到的n的最后一位二进制数要么是1要么是0 和result的值进行或运算,是不会对result前面的数造成影响的
    public int reverseBits(int n) {
        //位运算
        int result = 0;
        //给定的是32为数 所以循环32次即可
        for(int i = 0;i < 32;i++){
            //lastBit = (n & 1)
            //result左移一位 腾出位置 放入lastBit
            result <<= 1;
            //result直接 | lastBit=(n & 1)  反正result最开始每一位都是0 所以或的结果最终就是lastBit
            result |= (n & 1);
            //将原二进制数右移一位 继续获得当前最后一位的二进制数
            //>>>为无符号右移 无论最高位是什么 都填0
            n >>>= 1;
        }
        return result;
    }

题目四:位1的个数

题目描述:编写一个函数,输入是一个无符号整数(以二进制串的形式)n,返回其二进制表达式中数字位数为 '1' 的个数(也被称为汉明重量)。

思路:位运算,循环二进制数n,如果n不为0 ,就将其减去1,并更新n的值(采用与运算的方式)。

代码实现:

public int hammingWeight(int n) {
        int result = 0;
        //有几个1循环几次
        while(n != 0){
            n = n & (n-1);
            result ++;
        }
        return result;
}

小细节补充:n & (n-1)操作的个人理解(查阅过资料)

n-1操作: 如果最低位为1 则直接减去 如果最低位为0 则向前借一位,如果前面也是0 则一直往前借 直到借到值然后拿过来运算。最低位减去1后为0,被借走的那一位也要相应的减去1。(相当于每次将n的最后一位1减去)
n&(n - 1)操作: 就是用旧的n来和新减去1的n进行与操作(两个都是1结果才为1否则为0),得到一个新的n。且既然进了循环证明肯定是有1的,所以result就加一,然后继续进行n&(n-1)操作。(相当于更新n的值)

题目四:比特位计数

题目描述:给你一个整数 n ,对于 0 <= i <= n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n + 1 的数组 ans 作为答案。

思路:使用汉明重量思想,对每一个数进行取最后一个1,累加数量

代码实现:第一个是旧版本,第二个是优化过后的

    
//旧版本
    public int[] countBits(int n) {
        int[] result = new int[n+1];
        int count = 0;
        //使用汉明重量的思想,将每一个i进行循环计算位1的个数
        for(int i = 1;i <= n;i++){
            int tmp = i;
            while(tmp != 0){
                tmp = (tmp & (tmp-1));
                count ++;
            }
            result[i] = count;
            count = 0;
        }
        return result;
    }
/*
    优化:一次循环
    */
    public int[] countBits(int n){
        int[] result = new int[n+1];
        for(int i = 1;i <= n;i++){
            result[i] = result[i&(i-1)] + 1;
        }
        return result;
    }

    
  

优化版本的解释:

因为0~n范围内是层次递增的,每一个i去掉一个1之后 他的值都是i-1 ,可以每次计算i去掉一个二进制1之后的结果再加上1的结果,赋值给当前i,就是当前i中1的个数了
           问题1:为什么还要加上一?
           因为要通过当前数的二进制减1之后,得到一个对应的索引,该索引位置上的值加上1就是当前数的1的个数
            如:4的二进制数中只有一个1  所在其减去一个1之后的二进制值结果是为0的,但是0位置上是没有1的,所以需要加1
                    5的二进制数中有两个1 ,所以在其减去一个1之后的二进制结果为0100 对应的就是十进制的4,而result[4]位置上的值是1,所以需要加一
总结:即:当前数的二进制减去一个1之后,在数组中对应位置上的值再加上1,就是该数的二进制1的个数,可以通过找规律发现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值