算法【Java】—— 位运算

devtools/2024/9/25 0:21:14/

位运算总结

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

确定一个数 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/

在这里插入图片描述


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

java">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

java">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) 即可

java">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/

在这里插入图片描述

java">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 即可

java">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 个比特位就可以保存数据的状态。

java">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 之间所有的数字进行异或运算,然后将数组里的所有数字和上一次异或的结果一起异或,这样就可以找到丢失的数字了。

java">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 进行相加的时候是需要进位的,所以我们可以通过两个操作数按位与再左移一位就可以知道哪一些比特位需要进行进位,再次重复上述操作,知道最后没有需要进位,就可以得到两个数字相加的结果。

java">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 个比特位,所以进行三十二次循环。

java">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 和数组所有的元素都进行划分就可以得到最终的两个数字了。

java">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.ppmy.cn/devtools/116727.html

相关文章

WEB攻防-JavaWweb项目JWT身份攻击组件安全访问控制

知识点&#xff1a; 1、JavaWeb常见安全及代码逻辑&#xff1b; 2、目录遍历&身份验证&逻辑&JWT&#xff1b; 3、访问控制&安全组件&越权&三方组件&#xff1b; 演示案例&#xff1a; JavaWeb-WebGoat8靶场搭建使用 安全问题-目录遍历&身份认…

Flink 中 Checkpoint 的底层原理和机制

Flink 的 Checkpoint 机制是 Apache Flink 在流式处理中的一个核心特性&#xff0c;保证了分布式数据流处理系统的 容错性。通过定期保存 状态快照&#xff08;checkpoint&#xff09;&#xff0c;即使在发生故障时&#xff0c;Flink 也可以恢复到之前的状态&#xff0c;确保处…

火车站高铁站站点时刻查询网站计算机毕设/动车站点时刻查询

创建一个关于火车站高铁站站点时刻查询的毕业设计项目&#xff0c;是一个非常实际且具有挑战性的任务。这样的项目不仅能帮助学生综合运用所学知识&#xff0c;还能够为用户提供便捷的服务。下面将详细说明项目的各个方面&#xff1a; 1. 需求分析 用户需求&am…

Python编码系列—Python适配器模式:无缝集成的桥梁

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

yolo介绍

YOLO&#xff08;You Only Look Once&#xff09;是一种目标检测算法。 一、主要特点 1. 速度快&#xff1a;YOLO 能够快速处理图像&#xff0c;实现实时目标检测。与其他一些目标检测算法相比&#xff0c;它在处理速度上具有明显优势&#xff0c;可以满足对实时性要求较高的应…

复选框选择示例【JavaScript】

这段代码实现的功能是一个简单的复选框示例&#xff0c;它可以进行全选、反选和取消选中操作。 实现功能&#xff1a; 1. 全选&#xff1a;当点击标签"全选"旁边的复选框时&#xff0c;该页面上所有具有"item"类的复选框都会被选中&#xff08;或者取消选…

OceanBase中Range 分区 和 Range Columns 分区

1. Range 分区和 Range Columns 分区的区别 Range 分区&#xff1a;只允许基于一个整型列&#xff08;INT 类型&#xff09;的值范围进行分区。通常适用于那些可以自然用整数来表达的值&#xff0c;如商品编号、用户 ID 等。OceanBase 限定 Range 分区的分区键为 INT 类型&…

[ffmpeg]音频格式转换

本文主要梳理 ffmpeg 中的音频格式转换。由于采集的音频数据和编码器支持的音频格式可能不一样&#xff0c;所以经常需要进行格式转换。 API 调用 常用 API struct SwrContext *swr_alloc(void); int swr_init(struct SwrContext *s); struct SwrContext *swr_alloc_set_opt…