剑指offer——位运算

这篇博客介绍了几种使用位运算解决算法问题的方法,包括摩尔投票法找数组中出现次数超过一半的数字,通过位移计算二进制中1的个数,利用异或操作找出数组中出现奇数次的数字,以及通过位运算判断数组中是否存在能被3整除的数字。此外,还讨论了如何利用位运算实现加法操作。这些技巧展示了位运算在算法设计中的高效性和灵活性。

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

(一)剑指Offer39. 数组中出现次数超过一半的数字

在这里插入图片描述
基本思路:
1.这道题最先想到也是最简单的思路就是用HashMap进行统计,或是将数组进行排序,中位数一定是超过一半的那个数字。
2.另一个方法是采用摩尔投票的方法,

(二)剑指Offer15. 二进制中1的个数

在这里插入图片描述
基本思路:
提取最低位,判断是否为1,并不断进行位右移。

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int total = 0;
        while(n != 0){
            if((n & 1) == 1){
                total ++;
            }
            n >>>= 1;//无符号右移
            
        }
        return total;
        
    }
}

(三)剑指 Offer 56 - I. 数组中数字出现的次数

在这里插入图片描述
基本思路:
异或操作的结果是,两数相同为0、不同则为该数。基于这一性质,我们将所有的数异或,得到的结果是出现奇数次的数字的异或结果。
这一题中,有两个数字只出现一次,故我们需要采用一定的方法将两个数字分离开。分离方法如下:首先将所有的数字异或,得到这两个数字异或的结果;找到异或结果中为1的一个位,在这个位上,两个数字是不同的。于是我们重新对所有数字进行分组,这个位是0的数字为一组,这个数字为1的数字为一组,并将两组分别异或,得到的结果就是这两个数字。

class Solution {
    public int[] singleNumbers(int[] nums) {
        //原始题:有一个数字只出现了一次,用异或
        //现在的变形题:两个数字只出现了一次,需要找到方法把他分开
        /*将所有的数字异或,得到一个至少有一位是1的结果,这个1的位表示两个数字不同,所以根据这个为1的为是0还是1将整个数组分为两组,
        再分别异或就能得到两个数字*/
        int orr = 0;
        for(int n : nums){
            orr ^= n;
        }//得到异或结果
        int low = 1;
        while((orr & low) == 0){
            low = low<< 1;
        }//找到为1的位
        List<Integer> list1 = new ArrayList<>();
        List<Integer> list2 = new ArrayList<>();
        for(int m : nums){
            if((m & low) == 0){
                list1.add(m);
            }else{
                list2.add(m);
            }
        }
        int num1=0,num2=0;
        for(int i = 0; i < list1.size(); i++){
            num1^=list1.get(i);
        }
        for(int i = 0; i < list2.size(); i++){
            num2^=list2.get(i);
        }
        int[] res = {num1,num2};
        return res;
    }
}

(四)剑指 Offer 56 - II. 数组中数字出现的次数 II

在这里插入图片描述
基本思路:
1.简单的方法是进行遍历统计,存储这些数字的每一位的和,找到能被3整除的。
代码如下:

class Solution {
    public int singleNumber(int[] nums) {
        /*假设不存在这个 single number,那么 nums 中所有元素的二进制形式加起来之后,每一位必然都可以被 3 整除。因为每个数字都出现了三次,那么它们的二进制形式每一位也都出现了三次,那加起来之后每一位当然可以被 3 整除了*/
        int[] binary = new int[32];  
        for(int n : nums){
            for(int i = 0; i < 32; i++){
                binary[i] += n & 1;
                n >>= 1;
            }//最低位存在0
        }
        // for(int i=0; i<6; i++){
        //     System.out.println(i+":  "+binary[i]);
        // }
        int res = 0;
        for(int i = 31; i >= 0; i--){
            // System.out.println(i+"  "+res);
            res <<= 1;
            if(binary[i] % 3 == 1){
                res += 1;
            }
        }
        return res;
    }
}

2.一个巧妙的方法是:考虑数字的二进制形式,对于出现三次的数字,各 二进制位 出现的次数都是 3 的倍数。
因此,统计所有数字的各二进制位中 1的出现次数,并对 3求余,结果则为只出现一次的数字。
在这里插入图片描述

(五)剑指 Offer 64. 求1+2+…+n

在这里插入图片描述
基本思路:
这道题基于&&运算的短路特性。A && B时,若 A 为 true,则计算并返回表达式 B 的 bool 值;若A 为 false,则直接返回 false。基于这一特性,这道题由于限制,只能采用递归方法,递归的代码如下,显然递归方法中的终止判断却无法实现。
在这里插入图片描述
但是,如果基于短路特性,令当n==1时,就不会执行后面的算式

class Solution {
    public int sumNums(int n) {
         /*&& 的短路特性
        A && B
        A 为 true,则计算并返回表达式 B 的 bool 值
        A 为 false,则直接返回 false
        所有的乘积,除了i
        */
        boolean x = (n > 1) && (n += sumNums(n - 1)) > 0;
        return n;
    }
}

(六)剑指 Offer 65. 不用加减乘除做加法

在这里插入图片描述

class Solution {
    public int add(int a, int b) {
        //没有加减乘除,只能用位运算
        //位运算可以直接对数值进行,不需要转化为二进制,这都是我们便于理解才转化的
        //二进制包括:&与,|或,~非,^异或
        int c = 0;
        while(b!= 0){
            //a用于存储异或后的结果,b用于存储进位后的结果
            /* 0 1 0 0 
               1 1 1 1
               --------异或 ---------与
               1 0 1 1      0 1 0 0
               与中存在1的位置,恰好应该向前进一位
            */
            c = (a&b)<<1;
            a = a^b;
            //此时转化为c与a相加
            b = c;
        }
        return a;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值