力扣—消失的数字(位运算)

文章目录

在写这个题目之前我们需要了解一下运算符^的一些性质:
• 交换律: A ^ B = B ^ A
• 异或运算满足交换律,即两个操作数的顺序可以互换。
• 结合律: (A ^ B) ^ C = A ^ (B ^ C)
• 异或运算满足结合律,即三个或更多操作数可以分组进行异或运算,而不影响最终结果。
• 自反性: A ^ A = 0
• 任何数与自身进行异或运算的结果都是0。
• 恒等元素: A ^ 0 = A
• 任何数与0进行异或运算的结果都是该数本身。
• 逆元素: A ^ 1 = ~A
• 任何数与1进行异或运算,结果等价于该数的按位取反(NOT)。
• 对加法的分配律: A ^ (B + C) = (A ^ B) + (A ^ C)
• 异或运算对加法运算满足分配律。
• 对乘法的分配律: A ^ (B * C) = (A ^ B) * (A ^ C)
• 异或运算对乘法运算满足分配律。
• 对AND的分配律: A ^ (B & C) = (A ^ B) & (A ^ C)
• 异或运算对AND运算满足分配律。
• 对OR的分配律: A ^ (B | C) = (A ^ B) | (A ^ C)
• 异或运算对OR运算满足分配律。
• 对异或的分配律: A ^ (B ^ C) = (A ^ B) ^ (A ^ C)
• 异或运算对自身也满足分配律。
• 双重否定: A ^ A ^ A = A
• 任何数与自身进行两次异或运算,结果仍然是该数本身。
• 与0异或: A ^ 0 = A
• 任何数与0进行异或运算,结果仍然是该数本身。
• 与自身异或: A ^ A = 0

丢失的数字

丢失的数字

给定一个包含 0, n 中 n 个数的数组 nums ,找出 0, n 这个范围内没有出现在数组中的那个数。

示例 1:

输入:nums = 3,0,1

输出:2

解释:n = 3,因为有 3 个数字,所以所有的数字都在范围 0,3 内。2 是丢失的数字,因为它没有出现在 nums 中。

示例 2:

输入:nums = 0,1

输出:2

解释:n = 2,因为有 2 个数字,所以所有的数字都在范围 0,2 内。2 是丢失的数字,因为它没有出现在 nums 中。

解题思路:

直接利用A ^ A = 0这个性质即可:

代码实现

java 复制代码
class Solution {
    public int missingNumber(int[] nums) 
    {
        int ret=0;
        for(int i=0;i<nums.length;i++)
        {
            ret^=nums[i];
        }
        for(int i=0;i<=nums.length;i++)
        {
            ret^=i;
        }
        return ret;
    }
}

只出现一次的数字|||

只出现一次的数字|||

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

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

示例 1:

输入:nums = 1,2,1,3,2,5

输出:3,5

解释:5, 3 也是有效的答案。

示例 2:

输入:nums = -1,0

输出:-1,0

解题思路和消失的两个数字 几乎一样

可以先看消失的两个数字的题解

java 复制代码
class Solution {
    public int[] singleNumber(int[] nums) 
    {
        int temp=0;
        for(int i=0;i<nums.length;i++)
        {
            temp^=nums[i];
        }
        int diff=0;
        while(((temp>>diff)&1)!=1)
        {
            diff++;
        }
        int a=0,b=0;
        int[] ret=new int[2];
        for(int x:nums)
        {
            if(((x>>diff)&1)==1)
            {
               a^=x;
            }
            else
            {
                b^=x;
            }
        }
        ret[0]=a;
        ret[1]=b;
        return ret;
    }
}

消失的两个数字

消失的两个数字

本题就是丢失的数字+260只出现⼀次的数字III组合起来的题。

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

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

示例 1:

输入: 1

输出: 2,3

示例 2:

输入: 2,3

输出: 1,4

提示:

nums.length <= 30000

解题思路:

• 异或所有数字:首先,代码遍历数组nums中的所有数字,并将它们与一个临时变量tmp进行异或运算。异或运算有一个性质,即一个数与自己异或结果为0,任何数与0异或结果仍然是那个数。因此,如果数组中有两个数字缺失,那么这两个数字不会对tmp产生影响,tmp将包含数组中所有数字的异或结果以及1到nums.length + 2(包括缺失的两个数字)的异或结果。

• 找出不同的比特位:接下来,代码找出tmp中第一个为1的比特位,这个比特位就是缺失的两个数字不同的比特位。这是因为缺失的两个数字在这个比特位上必然一个为0,一个为1,而其他所有数字在这个比特位上要么都是0,要么都是1。

• 分类异或:然后,代码根据这个不同的比特位将数组中的数字分为两类,并分别进行异或运算。一类是在这个比特位上为1的数字,另一类是在这个比特位上为0的数字。由于缺失的两个数字必然分别属于这两类,所以最终的两个结果就是缺失的两个数字。

• 返回结果:最后,代码返回一个包含两个缺失数字的数组ret。

代码实现:

java 复制代码
class Solution {
   public int[] missingTwo(int[] nums) 
 {
 // 1. 先把所有的数异或在⼀起 
    int tmp = 0;
    for(int x : nums) tmp ^= x;
    for(int i = 1; i <= nums.length + 2; i++) tmp ^= i;
    // 2. 找出 a,b 两个数⽐特位不同的那⼀位 
     int diff = 0;
     while(true)
     {
      if(((tmp >> diff) & 1) == 1) break;
       else diff++;
       }
      // 3. 将所有的数按照 diff 位不同,分两类异或 
      int[] ret = new int[2];
      //第一个for循环,将数组分为两类
      for(int x : nums)
     if(((x >> diff) & 1) == 1) ret[1] ^= x;
      else ret[0] ^= x;
      //第二个for循环是为了通过A ^ A = 0这个性质去掉不需要的数字,而添加到消失的数字
      for(int i = 1; i <= nums.length + 2; i++)
      if(((i >> diff) & 1) == 1) ret[1] ^= i;
        else ret[0] ^= i;
     return ret;
 }
}

大家有什么想法和意见可以留言评论。

相关推荐
倒头就睡的小比特3 天前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!3 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
猎头南楼3 天前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
m0_547486663 天前
《数据结构教程》全套 PPT课件2026
数据结构
旖旎夜光3 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wzdark3 天前
大规模并行计算中的负载均衡算法研究4
算法
Because_of_Her13 天前
并查集-听课笔记
笔记·算法·并查集
码流子3 天前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
another heaven3 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
wzdark3 天前
从算法设计模式看编程思维的抽象能力4
算法