位运算总结(Java)

目录

位运算概述

位运算符

位运算的优先级

位运算常见应用

1. 给定一个数n,判断其二进制表示中的第x位是0还是1

 2. 将数n的二进制表示中的第x位修改为1

3. 将数n的二进制表示中的第x位修改为0

4. 位图

例题:判断字符是否唯一

5. 提取数n的二进制表示中的最右侧的1(lowbit)

6. 去掉数n的二进制表示中的最右侧的1

例题:位1的个数

7. 异或(^)运算的运算律

例题:只出现一次的数字

位运算练习

练习1:两整数之和

练习2:只出现一次的数字II

练习3:只出现一次的数字III

练习4:消失的两个数字


位运算概述

位运算:计算机中的数据在内存中是以二进制形式进行存储的,而位运算是对二进制数进行操作的运算,能够按位对数字进行操作

位运算符

(1)与运算符(&):如果两个二进制数的同一位都为1,则结果为1,否则为0。(有0为0)

(2)或运算符(|):如果两个二进制数的同一位至少有一个为1,则结果为1,否则为0。(有1为1)

(3)异或运算符(^):如果两个二进制数的同一位不相同,则结果为1,否则为0。也可以理解为 无进位相加(即0 + 0 = 0;0 + 1 = 1;而当1+1时,结果为0,但不进位)

(4)取反运算符(~):将二进制数的每一位取反,即0变为1,1变为0。

(5)左移运算符(<<):将二进制数向左移动指定的位数,右边补0。

(6)右移运算符(>>):将二进制数向右移动指定的位数,左边补0或者补1(取决于原数字的符号位)。

(7)复合赋值运算符:

&=        a&=b   同      a=a&b

|=         a|=b     同     a=a|b

>>=      a>>=b  同     a=a>>b

<<=      a<<=b  同      a=a<<b

注:对于负数的位操作,一般会使用补码表示法。在补码表示法中,最高位为符号位,0表示正数,1表示负数。位操作对于负数的结果仍然是以补码形式表示的。

位运算的优先级

常见位运算的优先级顺序:

(1)括号(()):括号可以用来改变运算符的结合性和优先级。

(2)取反运算符(~):取反运算符的优先级较高。

(3)左移运算符(<<)、右移运算符(>>)、无符号右移运算符(>>>):左移和右移运算符的优先级相同,且比与、或、异或运算符低。

(4)与运算符(&):与运算符的优先级较低。

(5)异或运算符(^):异或运算符的优先级较低于与运算符。

(6)或运算符(|):或运算符的优先级最低。

注:位运算符的优先级较低,因此在进行位运算操作时,可以使用括号来明确运算符的优先级和结合性

位运算常见应用

1. 给定一个数n,判断其二进制表示中的第x位是0还是1

例如:

在这里,我们从右侧第零位开始计数 

要判断一个数的第x位是0还是1,只需要将x向右移动x位(>> x),再与(&) 上1,即可判断,

(n >> x) & 1 

 2. 将数n的二进制表示中的第x位修改为1

例如:

要将第x位上的0修改为1,我们可以想到或(|)运算符,当两个二进制数的同一位至少有一个为1,则该位结果为1

因此,我们可以将1左移x位再让n与其进行或运算,即n |= (1 << x)

3. 将数n的二进制表示中的第x位修改为0

与将第x位修改为1类似,我们可以想到与(&)运算符,当两个二进制数的同一位至少有一个为0,则该位结果为0

因此,我们将1左移x位,再对其按位取反,这样就使得第x位为0,其他位都为1,然后再进行与运算,即 n &= (~ (1 << x))

4. 位图

位图是一种数据结构,类似于数组,在数组中每个下标标识一个元素,而位图使用每个位来标识一种状态

 以上图为例,int类型的整数有32个比特位,每个比特位标识一个元素,一个元素有两种状态(0或1)

接下来我们以一道例题来进一步了解和使用位图:

例题:判断字符是否唯一

题目链接:

 面试题 01.01. 判定字符是否唯一 - 力扣(LeetCode)

题目描述:

实现一个算法,确定一个字符串 s 的所有字符是否全都不同。

示例 1:

输入: s = "leetcode"
输出: false 

示例 2:

输入: s = "abc"
输出: true

限制:

  • 0 <= len(s) <= 100
  • s[i]仅包含小写字母
  • 如果你不使用额外的数据结构,会很加分。

思路分析:要判断字符串中是否有字符相同,我们可以使用哈希表来统计每个字符的个数,由于字符串中仅包含小写字母,我们可以使用int类型的数组(int[26])来标识26个小写字母(即0下标位置表示a的个数,1下标位置表示b的个数...),然后统计每个字符的个数。

由于只需要判断是否有字符相同,我们也可以使用位图,使用int类型的变量bitMap来作为“数组”,其中26位来标识26个小写字母,当该字符未出现过时(即对应二进制位为0),将对应二进制位修改为1,而当该字符出现过时(即对应二进制位为1),则可判断有字符相同,返回false

代码实现:

class Solution {public boolean isUnique(String astr) {char[] s = astr.toCharArray();if(s.length > 26) return false;int bitMap = 0;for(char x : s){int index = x - 'a';if((bitMap & (1 << index)) == 0){bitMap |= (1 << index);}else{return false;}}return true;}
}

5. 提取数n的二进制表示中的最右侧的1(lowbit)

要想提取出n中最右侧的1,只需将 n & (-n)

我们可以发现:将 n 转换为 -n(补码) 后,最右侧1 的左边区域(不包括最右侧1)全部变相反,此时,再将n & (-n),就只剩下最右侧的1

6. 去掉数n的二进制表示中的最右侧的1

去掉最右侧的1,只需将 n & (n - 1)

 我们可以发现:将 n 转换为 n-1 后,最右侧1 的右边区域(包括最右侧1)全部变相反,此时,再将n & (n-1),就能够去掉最右侧的1了

我们以一道例题进行练习:

例题:位1的个数

题目链接:

191. 位1的个数 - 力扣(LeetCode)

题目描述:

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

示例 1:

输入:n = 00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。

示例 2:

输入:n = 00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。

示例 3:

输入:n = 11111111111111111111111111111101
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。

思路分析:

题目要求我们计算整数n的二进制表示中的1的个数,可以通过判断每一位是否为1((n >> x) & 1)求出1的个数,但我们知道n & (n-1)能够去掉最右侧的1,因此我们只需计算能够去掉多少个1,即可求出1的个数

代码实现:

public class Solution {// you need to treat n as an unsigned valuepublic int hammingWeight(int n) {int sum = 0;while(n != 0){n = n & (n-1);sum ++;}return sum;}
}

 而题目:

338. 比特位计数 - 力扣(LeetCode)

461. 汉明距离 - 力扣(LeetCode)

也是类似的解题思路,大家可以自行练习

7. 异或(^)运算的运算律

a ^ 0 = a

a ^ a = 0

a ^ b ^ c = a ^ (b ^ c)

我们以一道例题来进一步掌握异或运算的运算律:

例题:只出现一次的数字

题目链接:

136. 只出现一次的数字 - 力扣(LeetCode)

题目描述:

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

你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。

示例 1 :

输入:nums = [2,2,1]
输出:1

示例 2 :

输入:nums = [4,1,2,1,2]
输出:4

示例 3 :

输入:nums = [1]
输出:1

思路分析:题目告诉我们数组中只有一个元素出现了一次,其他的都出现了两次,且a ^ a = 0,因此我们只需要将数组所有元素异或,出现两次的元素异或后都变为0,最后只剩下出现一次的元素a ^ 0 = a

代码实现:

class Solution {public int singleNumber(int[] nums) {int ret = nums[0];for(int i = 1; i < nums.length; i++){ret = ret ^ nums[i];}return ret;}
}

位运算练习

练习1:两整数之和

题目链接:

 371. 两整数之和 - 力扣(LeetCode)

题目描述:

给你两个整数 a 和 b ,不使用 运算符 + 和 - ,计算并返回两整数之和。

示例 1:

输入:a = 1, b = 2
输出:3

示例 2:

输入:a = 2, b = 3
输出:5

思路分析:不能使用运算符 + 和 - ,则我们可以考虑使用位运算来解决这个问题

异或(^)运算相当于无进位相加,在无进位的情况下(0 + 0 = 0,0 + 1 = 1)

接下来,我们考虑进位的情况:当该位上出现 1 + 1 时,则需要进位(即 1 + 1 = 10)而有需要进位的位为(a & b),进位后为(a & b)<< 1

因此,我们可以考虑将整数a 和 b的和,分为无进位加法的结果和进位结果的和

具体过程为:

以15和9为例:

1.先将每一位相加,且不考虑进位。二进制满2进位,即1 + 1 = 10,此时不考虑进位,因此,可以通过异或实现不考虑进位的相加,即 1 + 1 = 0,0 + 0 = 0,1 + 0 = 1,此时1111 + 1001 = 0110

2.找出进位的数。当出现1 + 1时,产生进位,我们可以通过两个数按位与找到这些存在进位的数,再将其向左移动1位,实现进位

3.将1和2得到的数字相加,由于相加不能使用加法,即重复1、2步骤,模拟实现加法,当进位为0时,即不再产生进位,此时异或的结果即为两个数相加的结果

代码实现:

class Solution {public int getSum(int a, int b) {while(b != 0){int carry = (a & b) << 1;//进位a = a ^ b;//无进位b = carry;}return a;}
}

练习2:只出现一次的数字II

题目链接:

 137. 只出现一次的数字 II - 力扣(LeetCode)

题目描述:

给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法且使用常数级空间来解决此问题。

示例 1:

输入:nums = [2,2,3,2]
输出:3

示例 2:

输入:nums = [0,1,0,1,0,1,99]
输出:99

提示:

  • 1 <= nums.length <= 3 * 104
  • -231 <= nums[i] <= 231 - 1

思路分析:由于只有一个元素出现了一次,其他n个元素元素都出现了三次,那么对于每一位都有以下四种情况:

1. 3n个0 + 1个0

2. 3n个0 + 1个1

3. 3n个1 + 1个0

4. 3n个1 + 1个1

对其模3(%3)可得:

1. 3n个0 + 1个0  (%3) -> 0

2. 3n个0 + 1个1  (%3) -> 1

3. 3n个1 + 1个0  (%3) -> 0

4. 3n个1 + 1个1  (%3) -> 1

即只出现一次的元素的二进制位,因此,我们只需求出出现一次的元素的每一位,即可求出该元素 

代码实现:

class Solution {public int singleNumber(int[] nums) {int ret = 0;for(int i = 0; i < 32; i++){int count = 0;for(int j = 0; j < nums.length; j++){count += ((nums[j] >> i) & 1);}count %= 3;ret = ret | (count << i);}return ret;}
}

练习3:只出现一次的数字III

题目链接:

 260. 只出现一次的数字 III - 力扣(LeetCode)

题目描述:

给你一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。

你必须设计并实现线性时间复杂度的算法且仅使用常量额外空间来解决此问题。

示例 1:

输入:nums = [1,2,1,3,2,5]
输出:[3,5]
解释:[5, 3] 也是有效的答案。

示例 2:

输入:nums = [-1,0]
输出:[-1,0]

示例 3:

输入:nums = [0,1]
输出:[1,0]

提示:

  • 2 <= nums.length <= 3 * 104
  • -231 <= nums[i] <= 231 - 1
  • 除两个只出现一次的整数外,nums 中的其他数字都出现两次

思路分析:与只出现一次的数字类似,但此题是两个元素只出现了一次,我们同样可以利用异或的运算律,将所有元素异或,此时得到两个只出现一次的元素的异或结果

如何得到这两个元素呢?

由于这两个元素一定不相同(若相同则异或结果为0,不符合题目中描述),我们可以通过提取结果中最右侧的1(lowbit),并将数组按照该位是否为1分为两组元素,这样,两个只出现一次的数字就被分到了不同的组里,此时再进行异或,就可得到这两个元素

代码实现:

class Solution {public int[] singleNumber(int[] nums) {int ret = nums[0];for(int i = 1; i < nums.length; i++){ret ^= nums[i];}//得到两个数的异或结果int ret1 = ret & (-ret);//找到最低位1int ret2 = 0;for(int i = 0; i < nums.length; i++){if((nums[i] & ret1) == 0){ret2 ^= nums[i];}}ret1 = ret2 ^ ret;return new int[] {ret1, ret2};}
}

练习4:消失的两个数字

题目链接:

 面试题 17.19. 消失的两个数字 - 力扣(LeetCode)

题目描述:

给定一个数组,包含从 1 到 N 所有的整数,但其中缺了两个数字。你能在 O(N) 时间内只用 O(1) 的空间找到它们吗?

以任意顺序返回这两个数字均可。

示例 1:

输入: [1]
输出: [2,3]

示例 2:

输入: [2,3]
输出: [1,4]

提示:

  • nums.length <= 30000

思路分析:

数组中缺失两个数字,设数组的长度为len,则所有元素为1 到 len+2,由于其中缺失两个数字,若将数组中所有元素和1 - len + 2看做一个整体,则此时就变为两个数字只出现一次,其他数字出现两次,此时就和 只出现一次的数字III 相同了,接下来按照 只出现一次的数字III 的解题思路来解题就可以解决该问题

代码实现:

class Solution {public int[] missingTwo(int[] nums) {int len = nums.length;int ret = (len + 2) ^ (len + 1);//求出两个数异或的结果for(int i = 0; i < nums.length; i++){//所有元素异或结果ret ^= nums[i];ret ^= (i+1);}int ret1 = ret & (-ret);//找到最低位1int ret2 = 0;for(int i = 0; i < len; i++){if((nums[i] & ret1) == 0){ret2 ^= nums[i];}}for(int i = 1; i <= len + 2; i++){if((i & ret1) == 0){ret2 ^= i;}}ret1 = ret2 ^ ret;return new int[] {ret1, ret2};}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/682405.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《区块链公链数据分析简易速速上手小册》第5章:高级数据分析技术(2024 最新版)

文章目录 5.1 跨链交易分析5.1.1 基础知识5.1.2 重点案例&#xff1a;分析以太坊到 BSC 的跨链交易理论步骤和工具准备Python 代码示例构思步骤1: 设置环境和获取合约信息步骤2: 分析以太坊上的锁定交易步骤3: 跟踪BSC上的铸币交易 结论 5.1.3 拓展案例 1&#xff1a;使用 Pyth…

OCP的operator——(2)OLM

文章目录 了解OperatorOperator Lifecycle Manager&#xff08;OLM&#xff09;OLM概念和资源OLM是什么OLM资源Cluster service version&#xff08;CSV&#xff09;Catalog source定制catalog source的image模板目录健康需求 SubscriptionInstall planOperator groupOperator …

文件压缩炸弹,想到有点后怕

今天了解到一个概念&#xff0c;压缩炸弹。 参考&#xff1a; https://juejin.cn/post/7289667869557178404 https://www.zhihu.com/zvideo/1329374649210302464 什么是压缩炸弹 压缩炸弹&#xff08;也称为压缩文件炸弹、炸弹文件&#xff09;是一种特殊的文件&#xff0c;它…

面试:大数据和深度学习之间的关系是什么?

大数据与深度学习之间存在着紧密的相互关系&#xff0c;它们在当今技术发展中相辅相成。 大数据的定义与特点:大数据指的是规模(数据量)、多样性(数据类型)和速度(数据生成及处理速度)都超出了传统数据处理软件和硬件能力范围的数据集。它具有四个主要特点&#xff0c;通常被称…

【Java】零基础蓝桥杯算法学习——二分查找

算法模板一: // 数组arr的区间[0,left-1]满足arr[i]<k,[left,n-1]满足arr[i]>k;Scanner scan new Scanner(System.in);int[] arr {1,2,3,4,5};int left 0,right arr.length-1;int k scan.nextInt();while(left<right) {//leftright时退出循环int mid (leftrigh…

leetcode(双指针)11.盛最多水的容器(C++详细解释)DAY9

文章目录 1.题目示例提示 2.解答思路3.实现代码结果 4.总结 1.题目 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回…

【Django】Django项目部署

项目部署 1 基本概念 项目部署是指在软件开发完毕后&#xff0c;将开发机器上运行的软件实际安装到服务器上进行长期运行。 在安装机器上安装和配置同版本的环境[python&#xff0c;数据库等] django项目迁移 scp /home/euansu/Code/Python/website euansuxx.xx.xx.xx:/home…

OpenCV基础:用Python生成一幅随机的噪声图像

使用Python&#xff1a;生成一幅随机数值的灰度图像&#xff0c;图像大小为1616像素。借助OpenCV库。输出数值&#xff0c;并显示图像。 # -*- coding: utf-8 -*- """ Created on Wed Feb 14 21:49:09 2024author: 李立宗公众号&#xff1a;计算机视觉之光知识…

【QT+QGIS跨平台编译】之四十:【gsl+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、GSL介绍二、GSL下载三、文件分析四、pro文件五、编译实践一、GSL介绍 GSL(GNU Scientific Library)是一个开源的数值计算库,用于提供一系列常用的数学函数和算法。它为科学计算和数据分析提供了高效、可靠的工具。 GSL库提供了丰富的功能,包括数值积分、数值…

C++-带你深度理解string类的常见接口

1. 为什么学习string类&#xff1f; C语言中&#xff0c;字符串是以\0结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c;C标准库中提供了一些str系列的库函数&#xff0c;但是这些库函数与字符串是分离开的&#xff0c;不太符合OOP的思想&#xff0c;而且底层空间需…

“从根到叶:深入理解堆数据结构“

​​​​​​​ 一.堆的概念及实现 1.1堆的概念 在数据结构中&#xff0c;堆是一种特殊的树形数据结构。堆可以分为最大堆和最小堆两种类型。 最大堆&#xff1a;对于堆中的任意节点&#xff0c;其父节点的值都不小于它的值。换句话说&#xff0c;最大堆中的根节点是堆中的最…

AI论文速读 | 2024【综述】图神经网络在智能交通系统中的应用

论文标题&#xff1a;A Survey on Graph Neural Networks in Intelligent Transportation Systems 链接&#xff1a;https://arxiv.org/abs/2401.00713 作者&#xff1a;Hourun Li, Yusheng Zhao, Zhengyang Mao, Yifang Qin, Zhiping Xiao, Jiaqi Feng, Yiyang Gu, Wei Ju, …

PR:熟悉PR工作环境

新建项目 设置自己的页面布局 首选项

【Algorithms 4】算法(第4版)学习笔记 07 - 2.4 优先队列

文章目录 前言参考目录学习笔记1&#xff1a;API1.1&#xff1a;实现 demo 示例1.2&#xff1a;初级实现&#xff08;有序或无序的数组&#xff09;2&#xff1a;二叉堆2.1&#xff1a;完全二叉树2.2&#xff1a;二叉堆2.2.1&#xff1a;堆的表示2.2.2&#xff1a;属性2.3&…

Java 基于 SpringBoot+Vue 的智慧外贸平台的研究与实现,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

【Vue】Vue基础入门

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;Vue ⛺️稳重求进&#xff0c;晒太阳 Vue概念 是一个用于构建用户界面的渐进式框架优点&#xff1a;大大提高开发效率缺点&#xff1a;需要理解记忆规则 创建Vue实例 步骤&#xff1a; …

Arm发布新的人工智能Cortex-M处理器

Arm发布了一款新的Cortex-M处理器&#xff0c;旨在为资源受限的物联网&#xff08;IoT&#xff09;设备提供先进的人工智能功能。这款新的Cortex-M52声称是最小的、面积和成本效率最高的处理器&#xff0c;采用了Arm Helium技术&#xff0c;使开发者能够在单一工具链上使用简化…

小结与数字的魅力的开篇

小结 本系列主要介绍了一些排序算法&#xff0c;包括冒泡排序、快速排序、直接插入排序、希尔排序、简单选择排序、堆排序、归并排序、计数排序、桶排序和基数排序。 排序算法本身并不难&#xff0c;但其涉及的知识点却星罗棋布&#xff0c;其变化莫测的思路更让人难以捉摸&am…

移动机器人激光SLAM导航(五):Cartographer SLAM 篇

参考 Cartographer 官方文档Cartographer 从入门到精通 1. Cartographer 安装 1.1 前置条件 推荐在刚装好的 Ubuntu 16.04 或 Ubuntu 18.04 上进行编译ROS 安装&#xff1a;ROS学习1&#xff1a;ROS概述与环境搭建 1.2 依赖库安装 资源下载完解压并执行以下指令 https://pa…

Spring Boot 笔记 009 创建接口_更新用户基本信息

1.1.1 给User实体类添加校验 package com.geji.pojo;import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import jakarta…