类型题Ⅱ:位运算

类型题Ⅱ:位运算

文章目录

位运算 —— 异或

英文: exclusive OR,缩写 xor
数学符号:

    ⊕



   ⊕


⊕ **运算法则:** 




    a


    ⊕


    b


    =


    (


    ¬


    a


    ∧


    b


    )


    ∨


    (


    a


    ∧


    ¬


    b


    )



   a⊕b = (¬a ∧ b) ∨ (a ∧¬b)


a⊕b=(¬a∧b)∨(a∧¬b)

口诀: “相同为 0,相异为 1”——XOR 在英文里面的定义为:either one (is one), but not both, 即只有一个为真(1)时结果取真(1)
真值表:

A B ⊕ ⊕ ⊕
F F F
F T T
T F T
T T T

性质:

  • 交换律:A ^ B = B ^ A- 结合律:A ^ (B ^ C) = (A ^ B) ^ C- 恒等律:X ^ 0 = X,即任何数与 0 的异或都等于该数本身- 归零律:X ^ X = 0- 自反:A ^ B ^ B = A ^ 0 = A- 对于任意的 X: X ^ (-1) = ~X- 若 A ^ B = C,则 B ^ C = A # 相关题目

645. 错误的集合

集合 S 包含从1到 n 的整数。不幸的是,因为数据错误,导致集合里面某一个元素复制了成了集合里面的另外一个元素的值,导致集合丢失了一个整数并且有一个元素重复。
给定一个数组 nums 代表了集合 S 发生错误后的结果。你的任务是首先寻找到重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。

位运算解法:根据异或性质,用 1~n-1 的异或结果与错误数组做异或,得到的结果就是缺失的数字。

class Solution:
    def findErrorNums(self, nums: List[int]) -> List[int]:
        mask = xor0 = xor1 = 0

        for idx, num in enumerate(nums, 1):
            mask ^= idx ^ num
        bitmask = mask & -mask

        for idx, num in enumerate(nums, 1):
            if idx & bitmask:
                xor1 ^= idx
            if num & bitmask:
                xor1 ^= num

        xor0 = mask ^ xor1

        for num in nums:
            if num == xor0:
                return [xor0, xor1]
        return [xor1, xor0]

136. 只出现一次的数字

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

位运算解法:由于异或运算满足交换律和结合律,即KaTeX parse error: Double superscript at position 7: a ^ b ^̲ a = b ^ a ^ a …,所以对整个数组异或,就能将相同的数字抵消掉,最后只剩下单独的一个数字,即为要找的答案。

时间复杂度:

    O


    (


    n


    )



   O(n)


O(n),对长度为 n 的数组遍历一次<br> 空间复杂度:




    O


    (


    1


    )



   O(1)


O(1)

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        return reduce(lambda x,y: x ^ y, nums)

137. 只出现一次的数字 II

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

位运算解法

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        ones, twos = 0, 0
        for num in nums:
            ones = ones ^ num & ~twos
            twos = twos ^ num & ~ones
        return ones

剑指 Offer 56 - I. 数组中数字出现的次数

一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

位运算解法:在136. 只出现一次的数字的基础上,这里单独的是两个数字,考虑将原数组分成两组,将两个单独的数字分配到两个数组中,这样再按照 136 题的解法,分别做异或即可得到答案。

问题在于怎么恰好把两个单独的数字分到两组?由于所有数组异或的结果就是两个单独数字的异或结果,而结果的每一位为 0 或 1。如果是 1 表示该位不同,那么就可以任选一个为 1 的位置,按照该位置对原数组分割,如果为 0 就归第一组,否则归第二组。这样就能保证两个单独的数字被分到不同的组,同时相同的数字对儿能够被分到同一组。

在实际选择中,可以选择不为0的最低位进行分组。

解题过程:

  • 先对所有数据进行异或,得到两个只出现一次的数字的异或值- 在该异或值中找到任意为 1 的位置- 根据该位对所有数字进行分组- 每个分组进行异或,分别得到一个单独的数 时间复杂度:O(n),遍历数组两次
    空间复杂度:O(1)
class Solution:
    def singleNumbers(self, nums: List[int]) -> List[int]:
        ret = reduce(lambda x, y: x ^ y, nums)  # 整个数组异或 = 两个单独数的异或
        div = 1
        while div & ret == 0:
            div <<= 1  # 从右向左找第一个不为0的位置
        a, b = 0, 0
        for n in nums:
            if n & div:
                a ^= n
            else:
                b ^= n
        return [a, b]

剑指 Offer 56 - II. 数组中数字出现的次数 II

在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。

这道题和前面的137. 只出现一次的数字 II一样。

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        ones, twos = 0, 0
        for num in nums:
            ones = ones ^ num & ~twos
            twos = twos ^ num & ~ones
        return ones

不用加减乘除做加法

写一个函数,求两个整数之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号。

class Solution:
    def add(self, a: int, b: int) -> int:
        x = 0xffffffff
        a, b = a & x, b & x
        while b != 0:
            a, b = (a ^ b), (a & b) << 1 & x
        return a if a <= 0x7fffffff else ~(a ^ x)

求1+2+…+n

求 1+2+…+n ,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

# 递归
class Solution:
    def __init__(self):
        self.res = 0
    def sumNums(self, n: int) -> int:
        n > 1 and self.sumNums(n-1)  # 不用if
        self.res += n
        return self.res
posted @ 2021-01-06 13:51  刘桓湚  阅读(147)  评论(0编辑  收藏  举报