leetcode—-位运算(python)

位运算

    • 位运算基本知识
      • 1.与(&)运算的用途
      • 2.异或(^)的用途
      • 3.取反(~)
    • leetcode例题
      • 汉明距离
      • 只出现一次的整数
      • 只出现一次的数字(奇数)
      • 二进制1的个数
      • 交换数字
      • 比特位计数
      • 判断字符是否唯一

位运算基本知识

位运算概述

1.与(&)运算的用途

a)清零:如果想将一个单元清零,即使其全部二进制位为0,只要与一个各位都为零得数值相与,结果为0;

例如:0&a=0

b) 取一个数的指定位

例如:取数X=1010 1100的前四位,令Y=0000 1111,则X&Y=0000 1110

c) 判断奇偶:奇数末位为1,偶数末位为0,则 a&1==0 为偶数否则为奇数

2.异或(^)的用途

a)翻转指定位

例如:X=1010 1110 的第四位进行翻转,只需零Y的前四位为1,其余为哦,即Y=0000 1111,X^Y=1010 0001

b) 与零相异或值不变

c)交换两个数

3.取反(~)

a&~0=a,

a&~1=a-1(a为奇数)or a(a为偶数)

leetcode例题

汉明距离

题目描述:两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。给出两个整数 x 和 y,计算它们之间的汉明距离。
注意:0 ≤ x, y < 231.
思路分析:根据汉明距离的定义,我们可以利用异或运算,异或运算,如果对应二进制的数相同为0,不同为1,因为我们统计两个数相异或之后,有多少个位置是1就可以了,统计利用右移运算。

1
2
3
4
5
6
7
8
class Solution:
    def hammingDistance(self, x: int, y: int) -> int:
        num = 0
        z = x^y
        while z!=0:
            num += z&1
            z = z>>1
        return num

只出现一次的整数

题目描述:给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次(偶数)。找出那个只出现了一次的元素。

思路分析:(1)一个数组除了一个元素出现一次其余都出现两个,则出现两次的元素异或为0,而0与任何数异或值不变,那么我们用0与数组中每个元素异或,最后剩下的数就是那个出现一次的数;时间复杂度为O(n)

(2)我们统计数组中不重复的元素,令这些元素的和乘以2,这里我们多算了一个只出现一次的元素的值,因此将其与原数组相减得到的就是我们需要求的数。
在这里插入图片描述

只出现一次的数字(奇数)

题目描述:给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。

思路分析:(1)哈希表,空间换时间。

(2)位运算,如果我们能将一个数出现三次的时候能自动抵消为0的时候,最后剩下的就是只出现一次的数了。

(3)数学推导
在这里插入图片描述

二进制1的个数

题目描述:请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。

思路分析:(1)首先想到的是利用与运算,将该整数转换为二进制,每一位和1做与&运算,看看有多少个1。时间复杂度为O(logn)

(2)巧用n&(n-1),n-1意味着二进制数字 n 最右边的 1 变成 0 ,此 1 右边1的 0都变成 1,那么n&(n-1)则将n最右边1变成0,其余不变,即n有几个1我们就能做几次运算直到n为0;
在这里插入图片描述

交换数字

题目描述:编写一个函数,不用临时变量,直接交换numbers = [a, b]中a与b的值。

思路分析
(1)[a,b]\rightarrow [a-b,b]\rightarrow [a-b,b+(a-b)]\rightarrow [b+(a–b)-(a-b),a]\rightarrow [b,a]

(2) 我们知道异或的一个用途就是交换两个数,(ab)b=a,(ab)a=b
在这里插入图片描述

比特位计数

题目描述:给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。输入: 5 输出: [0,1,1,2,1,2]。
思路分析:(1)遍历0<=i<=num间的每一个数,然后求每个数的二进制数中的1的个数。我们知道求二进制数的1的个数,可以通过 n&(n-1)来求,n&(n-1)等于将n最右边的1变成0,
(2)奇偶数的动态规划
奇数的二进制数中的1的个数比它前一个数(偶数)的个数多一个,也就是它前一个数(偶数)最后一位的0变成1。
偶数的二进制数中1的个数等于它除以2的那个数的1的个数。
这样就可以利用动态规划来求解了,每个数可以通过之前求得数来得到。

1
2
3
4
5
6
7
8
9
class Solution:
    def countBits(self, num: int) -> List[int]:
        result = [0]*(num+1)
        for i in range(1,num+1):
            if 1 & i:
                result[i] = result[i-1] + 1
            else:
                result[i] = result[int(i/2)]
        return result

注意列表索引是整型,result[int(i/2)] 要加上int。

判断字符是否唯一

题目描述:”实现一个算法,确定一个字符串 s 的所有字符是否全都不同。
思路分析:(1)可以使用数据结构的话,用字典,或者哈希表都可以达到
(2)使用位运算:首先要看字符串是否是ASCII码,如果是,那么字符串长度大于128,那么一定是False
我们可以使用一个int变量记录相应的字符是否出现,首先通过计算字符char离“a”的距离d,然后利用位移,将对应的位置置为1,即通过将1左移d个位置记为move_bit,再与mark做与运算,与运算,都为1才为1,所以如果出现重复的字符,那么与运算后为0,否则,令mark与move_bit做或运算,保留1的位置。

1
2
3
4
5
6
7
8
9
10
11
class Solution:
    def isUnique(self, astr: str) -> bool:
        #return len(set(astr))==len(astr)
        mark = 0
        for char in astr:
            move_bit = ord(char)-ord("a")
            if mark&(1<<move_bit)!=0:
                return False
            else:
                mark |= 1<<move_bit
        return True