摘要

一、位运算原理与解题方法

二、位运算练习题目

2.1 不用加减乘除做加法

不用加减乘除做加法_牛客题霸_牛客网

package 位运算;

/**
 * @Classname JZ65不用加减乘除做加法
 * @Description TODO
 * @Date 2022/2/6 15:36
 * @Created by xjl
 */
public class JZ65不用加减乘除做加法 {

    public int Add(int num1, int num2) {
        while (num2 != 0) {
            // 负数左移会在低位补1,所以转化为无符号整数
            int c = (num1 & num2) << 1;
            num1 ^= num2;
            num2 = c;
        }
        return num1;
    }
}

2.2 二进制中1的个数

二进制中1的个数_牛客题霸_牛客网

package 位运算;

/**
 * @Classname JZ15二进制中1的个数
 * @Description
 * @Date 2022/2/6 21:28
 * @Created by xjl
 */
public class JZ15二进制中1的个数 {
    /**
     * @description 数字&(与)运算的跪着
     * 1 & 1  =  1
     * 0 & 1  = 0
     * 0 & 0  = 0
     * @param: n
     * @date: 2022/2/6 21:29
     * @return: int
     * @author: xjl
     */
    public int NumberOf1(int n) {
        int ans = 0;
        for (int i = 1; i <= 32; i++) {
            //判断最后一位是否为1
            if ((n & 1) == 1) {
                ans++;
            }
            // 让后右边移动一位
            n = n >> 1;
        }
        return ans;
    }

    public int NumberOf2(int n) {
        int ans = 0;
        while (n != 0) {
            ans++;
            n = n & (n - 1);
        }
        return ans;
    }
}

2.3 数值的整数次方

数值的整数次方_牛客题霸_牛客网

2.4 数组中只出现一次的两个数字

数组中只出现一次的两个数字_牛客题霸_牛客网

我们都知道异或运算:如果两个数一样则异或结果为0,不一样则异或结果为1。(二进制)

4 ⊕ 4 = 0,将4化为二进制为 0100

所以 0100

异或 0100

得到 0000

4 ⊕ 4 ⊕ 5 = 5

则 0100

 0100

 0101

得到 0101

我们可以看到上面的运算过程,因为4=4,两者相等异或结果为0。所以0异或任意数都等于任意数。

所以,当只有一个出现了一次的数字的时候,则只需要将全部数进行异或运算,运算结果就剩下了那个只出现一次的数字了。

public int[] singleNumber(int[] nums) {
    int x = 0;
    for(int num : nums)  // 1. 遍历 nums 执行异或运算
        x ^= num;
    return x;            // 2. 返回出现一次的数字 x
}
public int[] FindNumsAppearOnce (int[] array) {
 
        // 先将全部数进行异或运算,得出最终结果
        int tmp = 0;
        for(int num: array){
            tmp ^= num;
        }
 
        // 找到那个可以充当分组去进行与运算的数
        // 从最低位开始找起
        int mask = 1;
        while((tmp&mask) == 0){
            mask <<= 1;
        }
 
        // 进行分组,分成两组,转换为两组 求出现一次的数字 去求
        int a = 0;
        int b = 0;
        for(int num:array){
            if((num&mask) == 0){
                a ^= num;
            }else{
                b ^= num;
            }
        }
        // 因为题目要求小的数放前面,所以这一做个判断
        if(a > b){
            int c = a;
            a = b;
            b = c;
        }
        return new int[]{a,b};
    }

2.5 求解1到n的和

求1+2+3+...+n_牛客题霸_牛客网

package 位运算;

/**
 * @Classname JZ64求n和
 * @Description TODO
 * @Date 2022/2/6 22:22
 * @Created by xjl
 */
public class JZ64求n和 {
    int count = 1;

    public int Sum_Solution(int n) {
        for (int i = 2; i <= n; i++) {
            count = sum2(count, i);
        }
        return count;
    }

    private int sum2(int a, int b) {
        while (b != 0) {
            // 负数左移会在低位补1,所以转化为无符号整数
            int c = (a & b) << 1;
            a ^= b;
            b = c;
        }
        return a;
    }
}

博文参考

《leetcode》