文章目录
在写这个题目之前我们需要了解一下运算符^的一些性质:
• 交换律: 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;
}
}
大家有什么想法和意见可以留言评论。