Leedcode day5笔记 位运算

位运算

位运算与二进制简介

  • 位运算:在计算机内部,数是以「二进制(Binary)」的形式来进行存储。位运算就是直接对数的二进制进行计算操作,在程序中使用位运算进行操作,会大大提高程序的性能。
  • 二进制:由0和1两个数码来表示的数。二进制数中每一个 0 或每一个1都成为一个「位(Bit)」。请添加图片描述

二进制数的转换

二进制转十进制数:二进制数转换为十进制数的基本原理是将每个二进制位上的数字乘以 2 的该位权值,然后将所有结果相加。请添加图片描述
十进制转二进制:十进制数转二进制数的方法是,除二取余,逆序排列法。
106 ÷ 2 = 53 (余 0) 53 ÷ 2 = 26 (余 1) 26 ÷ 2 = 13 (余 0) 13 ÷ 2 = 6 (余 1) 6 ÷ 2 = 3 (余 0) 3 ÷ 2 = 1 (余 1) 1 ÷ 2 = 0 (余 1) 0 ÷ 2 = 0 (余 0) \begin{aligned} 106 \div 2 = 53 & \text{(余 0)} \cr 53 \div 2 = 26 & \text{(余 1)} \cr 26 \div 2 = 13 & \text{(余 0)} \cr 13 \div 2 = 6 & \text{(余 1)} \cr 6 \div 2 = 3 & \text{(余 0)} \cr 3 \div 2 = 1 & \text{(余 1)} \cr 1 \div 2 = 0 & \text{(余 1)} \cr 0 \div 2 = 0 & \text{(余 0)} \end{aligned} 106÷2=5353÷2=2626÷2=1313÷2=66÷2=33÷2=11÷2=00÷2=0(余 0(余 1(余 0(余 1(余 0(余 1(余 1(余 0
我们反向遍历每次计算的余数,依次是 0, 1 1 1 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0,即 01101010(2)。

位运算集成操作

在二进制的基础上,我们可以对二进制数进行相应的位运算。基本的位运算共有6种,分别是:「按位与运算」、「按位或运算」、「按位异或运算」、「取反运算」、「左移运算」、「右移运算」。

运算符描述规则
∣ \mid 按位或运算符只要对应的两个二进位有一个为 1 时,结果位就为 1。
&按位与运算符只有对应的两个二进位都为1时,结果位才为 1 。
< < << <<左移运算符将二进制数的各个二进位全部左移若干位。<<右侧数字指定了移动位数,高位丢弃,低位补 0 。
> > >> >>右移运算符对二进制数的各个二进位全部右移若干位。>> 右侧数字指定了移动数,低位丢弃,高位补 0 。
^按位异或运算符对应的两个二进位相异时,结果位为 1 ,二进位相同时则结果位为 0 。
~取反运算符对二进制数的每个二进位取反,使数字 1 变为 0 , 0 变为 1 。

按位与运算

按位与运算(AND):按位与运算符为 &。其功能是对两个二进制数的每一个二进位进行与运算。

规则:只有对应的两个二进位都为 1 时,结果位才为 1 。

举个例子,对二进制数 0111110 0 ( 2 ) 01111100_{(2)} 01111100(2) 0011111 0 ( 2 ) 00111110_{(2)} 00111110(2) 进行按位与运算,结果为 0011110 0 ( 2 ) 00111100_{(2)} 00111100(2) ,如图所示:请添加图片描述

按位或运算

按位或运算(OR):按位或运算符为 |。其功能对两个二进制数的每一个二进位进行或运算。

规则:只有对应的两个二进位都为 1 时,结果位才为 1 。

举个例子,对二进制数 0111110 0 ( 2 ) 01111100_{(2)} 01111100(2) 0011111 0 ( 2 ) 00111110_{(2)} 00111110(2) 进行按位与运算,结果为 0011110 0 ( 2 ) 00111100_{(2)} 00111100(2),如图所示:请添加图片描述

按位异或运算

按位异或运算(XOR):按位异或运算符为 ^。其功能是对两个二进制数的每一个二进位进行异或运算。

规则:对应的两个二进位相异时,结果位为 1,二进位相同时则结果位为 0。

举个例子,对二进制数 0100101 0 ( 2 ) 01001010_{(2)} 01001010(2) 0100010 1 ( 2 ) 01000101_{(2)} 01000101(2) 进行按位异或运算,结果为 0000111 1 ( 2 ) 00001111_{(2)} 00001111(2),如图所示:请添加图片描述

取反运算

取反运算(NOT):取反运算符为 ~。其功能是对一个二进制数的每一个二进位进行取反运算。

规则:使数字 1 变为 0,0 变为 1。

举个例子,对二进制数 0110101 0 ( 2 ) 01101010_{(2)} 01101010(2) 进行取反运算,结果如图所示:请添加图片描述

左移运算和右移运算

左移运算(SHL): 左移运算符为 <<。其功能是对一个二进制数的各个二进位全部左移若干(高位丢弃,低位补 0)。

举个例子,对二进制数 0110101 0 ( 2 ) 01101010_{(2)} 01101010(2) 进行左移 1 位运算,结果为 1101010 0 ( 2 ) 11010100_{(2)} 11010100(2),如图所示:请添加图片描述右移运算(SHR): 右移运算符为 >>。其功能是对一个二进制数的各个二进位全部右移若干位(低位丢弃,高位补 0)。

举个例子,对二进制数 0110101 0 ( 2 ) 01101010_{(2)} 01101010(2) 进行右移 1 位运算,结果为 0011010 1 ( 2 ) 00110101_{(2)} 00110101(2),如图所示:请添加图片描述

位运算的应用

只出现一次的数字

题目大意:给定一个非空整数数组nums,nums中除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现一次的元素。要求不能使用额外的存储空间。
示例

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

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

解题思路:要解决这个问题,我们可以利用异或运算(XOR)的性质。当我们使用异或运算对数组中的所有元素进行异或运算时,成对出现的数字最终会相互抵消变成 0,而唯一那个单独出现的数字将保留下来。

def singleNumber(nums):
    unique_number = 0
    for num in nums:
        unique_number ^= num
    return unique_number

# 示例
nums = [4, 1, 2, 1, 2]
result = singleNumber(nums)
print(result)  # 输出: 4

数字范围按位与

题目大意:给定两个整数 l e f t left left r i g h t right right,表示区间 [ l e f t , r i g h t ] [left, right] [left,right]。返回此区间内所有数字按位与的结果(包含 l e f t left left r i g h t right right端点)。
示例

输入:left = 5, right = 7
输出:4

输入:left = 1, right = 2147483647
输出:0

解题思路:按位与操作 & 对两个数的每一位进行比较,如果两个对应的位都是1,则结果的对应位为1,否则为0。
对于区间 [left, right],只有那些在所有数字中都保持不变的位(即高位部分)才可能在最终的按位与结果中保持为1。因此,我们需要找到 left 和 right 的最长公共前缀。
通过不断右移 left 和 right,直到两者相等,此时它们的值就是最长公共前缀。
记录下右移的次数。将得到的公共前缀左移回原来的位置,即得到了最终的按位与结果。

def rangeBitwiseAnd(left, right):
    shift = 0
    # 找到 left 和 right 的最长公共前缀
    while left < right:
        left >>= 1
        right >>= 1
        shift += 1
    # 将公共前缀左移回原来的位置
    return left << shift

left = 5
right = 7
result = rangeBitwiseAnd(left, right)
print(result)  # 输出: 4
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值