zoukankan      html  css  js  c++  java
  • 巧用异或

    异或规律

    异或有以下规律

    1. 0^N = N
    2. N^N = 0
    3. 交换律 a ^ b = b ^ a
    4. 结合律 a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c
    5. 自反性 a ^ b ^ a = b

    使用异或交换数据

    一般的交换方式, 利用临时变量:

    a = 1
    b = 2
    
    temp = a
    a = b
    b = temp
    

    但你也可以使用异或的方法交换:

    a = 1
    b = 2
    
    a = a ^ b  # 1 ^ 2
    b = a ^ b  # 1 ^ 2 ^ 2 = 1
    a = a ^ b  # 1 ^ 2 ^ 1 = 2
    

    三次异或操作, 交换两个变量的值

    注意: 异或交换变量时, 不能为引用类型, 否则为被清空

    解决一些算法题

    出现奇数次的 1 个数字

    问题位置: 剑指 Offer II 070. 排序数组中只出现一次的数字
    问题描述:
    给定一个只包含整数的有序数组 nums ,每个元素都会出现两次,唯有一个数只会出现一次,请找出这个唯一的数字。

    示例 1:
    输入: nums = [1,1,2,3,3,4,4,8,8]
    输出: 2

    示例 2:

    输入: nums = [3,3,7,7,10,11,11]
    输出: 10

    题解

    非常简单, 由于异或的自反性(a ^ b ^ a = b), 所以只要将全部数异或, 那么得到的肯定是只出现一次的那个数

    代码

    class Solution:
        def singleNonDuplicate(self, nums: List[int]) -> int:
            eor = 0
            for i in nums:
                eor = eor ^ i
            return eor
    
    

    出现奇数次的 2 个数字

    题目位置: 剑指 Offer 56 - I. 数组中数字出现的次数
    问题描述:
    一个整型数组nums里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。
    要求时间复杂度是 O(n),空间复杂度是 O(1)。

    示例 1:
    输入:nums = [4,1,4,6]
    输出:[1,6] 或 [6,1]

    示例 2:
    输入:nums = [1,2,10,4,1,4,3,3]
    输出:[2,10] 或 [10,2]

    题解

    假设不同的两个数为ab
    由于有两个数, 我们无法通过一次异或得到, 但是我们可以通过一次异或得到a ^ b
    由于ab不可能相等, 那么, a ^ b != 0, 即 a ^ b的二进制位一定至少会有一个 "1"

    # 如
    arr = [1, 1, 2, 2, 3, 4]
    
    # 全部异或得到 3 ^ 4 != 0
    
    # 二进制位:
      011
      100
    -------
      111
    
    

    根据这一点, 我们可以把数据分为两半: 某一位有"1"和某一位无"1", ab就分别在这两半中
    接下来, 只需要对这两半数据全部异或即可得到两个数ab

    思路已经清晰了, 现在的重点要确定 "某一位" 时第几位, 我们需要提取出来, 不然没将数对半分
    如何做呢? 记住 一个数最后位的 1 等于 一个数 与上 自己取反+1 即可, 下面是解释:

    eor = 101011100
    right_one = eor & (~eor + 1)
    
    """
    eor = 101011100
    ~eor = 010100011
    ~eor+1 = 0101000100
    
    & 0000000100
    """
    

    代码

    class Solution:
        def singleNumbers(self, nums: List[int]) -> List[int]:
            eor = 0
            # 同样先全部异或
            for i in nums:
                eor = eor ^ i
    
            # 确定eor最右边的1
            right_one = eor & (~eor + 1)
    
            eor2 = 0
            for i in nums:
                # 将数据分为两半, &right_one = 0 或 != 0
                if right_one & i == 0:
                    #  继续异或, 得到第一个数
                    eor2 = eor2 ^ i
    
            # eor ^ eor2 得到第二个数
            eor = eor ^ eor2
            return eor, eor2
    

    本文来自博客园,作者:403·Forbidden,转载请注明原文链接:https://www.cnblogs.com/lczmx/p/15785341.html

  • 相关阅读:
    使用jq.lazyload.js,解决设置loading图片的问题
    Write your first jQuery plugin
    如何在Less中使用使用calc
    web页面在ios下不支持fixed可用absolute替代的方案
    JavaScript内存优化
    js监听文本框内容变化
    动态绑定事件on
    CSS秘密花园:多边框
    2020—2021—1学期20202405《网络空间安全导论》第一周学习总结
    2020—2021—1学期20202405《网络空间安全导论》第五周学习总结
  • 原文地址:https://www.cnblogs.com/lczmx/p/15785341.html
Copyright © 2011-2022 走看看