当前位置: 首页 > article >正文

算法【Java】—— 位运算

位运算总结

位运算的运算符:按位与(&),按位或(|),按位异或(^),按位取反(~),还有移位操作符 <<,>>

确定一个数 n 的第 x 位是0 还是 1
(n >> x) & 1 等于 1 / 0 来进行判断

将 n 的第 x 位修改为 1
n |= (1 << x)

将 n 的第 x 位修改为0
n &= ~(1 << x)

提取 n 二进制最右侧的 1
n & -n

删除 n 二进制最右侧的 1
n & (n - 1)

异或运算的规律
a ^ a = 0
a ^ 0 = a
a ^ b ^ c = a ^ c ^ b (满足交换律)

位运算的优先级可以通过我们手动添加括号来解决,这样就可以减少我们的记忆负担了。

位图思想:和哈希表类似,只不过位图采用的是比特位标记的方式来记录数字。

实战演练

只出现一次的数字 Ⅰ

https://leetcode.cn/problems/single-number/

在这里插入图片描述


由于除了一个元素只出现一次,其他元素均出现了两次,所以我们可以将所有的数字进行异或运算,最后得到的结果就是只出现一次的元素。

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

只出现一次的数字 Ⅲ

https://leetcode.cn/problems/single-number-iii/

在这里插入图片描述


假设最后的答案分别是 a ,b

按照上一道题目的思路,我们将所有的数字进行异或得到的结果为 a ^ b

现在我们需要将他们两个分开来,如何分开?首先这两个数字一定是不相同的,那么在某一个比特位上一定不同,我们找到这个不同的比特位,然后根据这个不同的比特位最为划分标准,将数组所有的元素分成两组,这两组再分别进行异或操作,最后就会得到 a 与 b 这两个数字。

如何找到不同的比特位?因为异或的无进位相加(相同的异或结果为0,相异的异或结果为1),所有只要能找到比特位为1,这个位置就可以作为后续的判断标准。这里我们就可以使用n & -n 获取n 最后一位的 1

class Solution {
    public int[] singleNumber(int[] nums) {
        int sum = 0;
        for(int x : nums) {
            sum ^= x;
        }

        sum &= -sum;
        int ret1 = 0, ret2 = 0;
        for(int x : nums) {
            if((x & sum) == 0) {
                ret1 ^= x;
            } else {
                ret2 ^= x;
            }
        }

        return new int[]{ret1,ret2};
    }
}

位 1 的个数

https://leetcode.cn/problems/number-of-1-bits/

在这里插入图片描述


直接使用 n & (n-1) 即可

class Solution {
    public int hammingWeight(int n) {
        int count = 0;
        while(n != 0) {
            n &= (n-1);
            count++;
        }
        return count;
    }
}

比特位计数

https://leetcode.cn/problems/counting-bits/

在这里插入图片描述

class Solution {
    public int[] countBits(int n) {
        int[] ans = new int[n+1];
        for(int i = 0; i <= n; i++) {
            int count = 0;
            int tmp = i;
            while(tmp != 0) {
                tmp &= (tmp - 1);
                count++;
            }
            ans[i] = count;
        }
        return ans;
    }
}

汉明距离

https://leetcode.cn/problems/hamming-distance/

在这里插入图片描述


计算不同的二进制位数,首先进行异或运算,然后计算这个结果有多少个 1 即可

class Solution {
    public int hammingDistance(int x, int y) {
        int sum = x ^ y;
        int count = 0;
        while(sum != 0) {
            sum &= (sum-1);
            count++;
        }
        return count;
    }
}

判定字符是否唯一

https://leetcode.cn/problems/is-unique-lcci/description/

在这里插入图片描述


这里我们首先会想到哈希表,但是如果不适用额外的数据结构,我们可以考虑位图,用一个变量上的比特位来记录数据,正好字符串都是小写字母,也就是26种字母,使用 26 个比特位就可以保存数据的状态。

class Solution {
    public boolean isUnique(String astr) {
        if(astr.length() > 26) { //鹊巢原理
            return false;
        }
        int bitSet = 0;//位图
        char[] arr = astr.toCharArray();
        for(char x : arr) {
            if((1 << (x-'a') & bitSet) != 0) {
                return false;
            } 
            bitSet |= (1 << (x-'a'));
        }
        return true;
    }
}

丢失的数字

https://leetcode.cn/problems/missing-number/description/

在这里插入图片描述


这道题可以使用等差数列求和公式来做

当然这里是位运算专题,我们可以使用为运算来做,首先我们可以将 0 ~ n 之间所有的数字进行异或运算,然后将数组里的所有数字和上一次异或的结果一起异或,这样就可以找到丢失的数字了。

class Solution {
    public int missingNumber(int[] nums) {
        int sum = 0;
        for(int i = 0; i <= nums.length; i++) {
            sum ^= i;
        }
        for(int x : nums) {
            sum ^= x;
        }
        return sum;
    }
}

两整数之和

https://leetcode.cn/problems/sum-of-two-integers/description/

在这里插入图片描述


我们知道异或运算可以得到无进位相加的结果,我们知道当两个比特位都为 1 进行相加的时候是需要进位的,所以我们可以通过两个操作数按位与再左移一位就可以知道哪一些比特位需要进行进位,再次重复上述操作,知道最后没有需要进位,就可以得到两个数字相加的结果。

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

只出现一次的数字 Ⅱ

https://leetcode.cn/problems/single-number-ii/description/

在这里插入图片描述


只有一个元素出现一次,其他元素均出现三次,那么我们可以进行比特位计数,计算每一位上所有的数字的 1 的个数,最后将结果 %3 ,就会得到只出现一次的元素的那一位比特位上是 1 还是 0.

一个整型数据由有32 个比特位,所以进行三十二次循环。

class Solution {
    public int singleNumber(int[] nums) {
        int ans = 0;
        for(int i = 0; i < 32; i++) {
            int count = 0;
            for(int x : nums) {
                if(((1 << i) & x) != 0) {
                    count++;
                }
            }
            if(count % 3 == 1) {
                ans |= (1 << i);
            }
        }
        return ans;
    }
}

消失的两个数字

https://leetcode.cn/problems/missing-two-lcci/

在这里插入图片描述


这道题我们先将 1 ~ n 和数组所有的数字异或就可以得到消失的两个数字的异或结果(这里记为 a ^ b),现在就是分离他们了,很简单,和上面一样,找到最后的比特位为 1,以这个为标准开始划分,将 1 ~ n 和数组所有的元素都进行划分就可以得到最终的两个数字了。

class Solution {
    public int[] missingTwo(int[] nums) {
        int n = nums.length;
        int sum = 0;
        for(int i = 1; i <= n + 2; i++) {
            sum ^= i;
        }
        for(int x : nums) {
            sum ^= x;
        }

        sum &= -sum;
        int ret1 = 0, ret2 = 0;
        for(int i = 1; i <= n + 2; i++) {
            if((i & sum) != 0) {
                ret1 ^= i;
            } else {
                ret2 ^= i;
            }
        }
        for(int x : nums) {
            if((x & sum) != 0) {
                ret1 ^= x;
            } else {
                ret2 ^= x;
            }
        }
        return new int[]{ret1,ret2};
    }
}

http://www.kler.cn/news/325189.html

相关文章:

  • python中logging的用法
  • python基础库
  • 铺铜修改后自动重铺
  • 第十一章 【前端】调用接口(11.1)——Vite 环境变量
  • Redis(初步认识和安装)
  • 智慧城市交通管理中的云端多车调度与控制
  • vue打包后的dist文件如何启动测试
  • Midjourney参数详解
  • 经纬仪应用前景
  • leetcode刷题day29|贪心算法Part03( 134. 加油站、135. 分发糖果、860.柠檬水找零、406.根据身高重建队列)
  • 建筑资质应该怎么选?
  • LeetCode 每日一题 2024/9/23-2024/9/29
  • Java项目实战II基于Java+Spring Boot+MySQL的网上摄影工作室(源码+数据库+文档)
  • Qemu开发ARM篇-5、buildroot制作根文件系统并挂载启动
  • 常见字符函数和字符串函数(上)
  • 在Linux中修改vm.max_map_count参数的步骤
  • InternVL 微调实践
  • C#里使用最简单的线程调用界面更新的方法
  • 【蚂蚁HR-注册/登录安全分析报告】
  • 基于大数据技术的颈椎病预防交流与数据分析及可视化系统
  • 【Webpack】优化前端开发环境的热更新效率
  • 上交所系统被股民买崩了?原因竟然是...
  • 宠物智能听诊器科技赋能宠物医疗
  • ad布线的常见错误123
  • JavaScript网站设计案例:如何构建一个交互性强、性能优异的网站
  • win10系统K8S安装教程
  • MYSQL的安装和升级
  • 【unity进阶知识4】封装unity协程工具,避免 GC(垃圾回收)
  • Vue76 编程式路由导航
  • 云手机的默认ip地址是什么