今天做LeetCode发现一个比较有趣的性质,做下笔记
给你一个仅由整数组成的有序数组,其中每个元素都会出现两次,唯有一个数只会出现一次。
请你找出并返回只出现一次的那个数。
你设计的解决方案必须满足 O(log n) 时间复杂度和 O(1) 空间复杂度。
输入: nums = [1,1,2,3,3,4,4,8,8]
输出: 2
输入: nums = [3,3,7,7,10,11,11]
输出: 10
解析:利用按位异或的性质,可以得到mid 和相邻的数之间的如下关系,其中 ⊕ 是按位异或运算符:
当 mid 是偶数时,mid + 1= mid ⊕ 1;
当 mid 是奇数时,mid - 1 = mid ⊕ 1。
因此在二分查找的过程中,不需要判断 \textit{mid}mid 的奇偶性,mid 和 mid⊕1 即为每次需要比较元素的两个下标。
public class Solution {
public int SingleNonDuplicate(int[] nums) {
int low = 0, high = nums.Length - 1;
while (low < high) {
int mid = (high - low) / 2 + low;
if (nums[mid] == nums[mid ^ 1]) {
low = mid + 1;
} else {
high = mid;
}
}
return nums[low];
}
}
1. a ⊕ a = 0
2. a ⊕ 0 = a
3. a ⊕ b = b ⊕ a
4. a ⊕b ⊕ c = a ⊕ (b ⊕ c) = (a ⊕ b) ⊕ c;
5. d = a ⊕ b ⊕ c 可以推出 a = d ⊕ b ⊕ c.
6. a ⊕ b ⊕ a = b.
7. 若x是二进制数0101,y是二进制数1011
则x⊕y=1110
只有在两个比较的位不同时其结果是1,否则结果为0
即“两个输入相同时为0,不同则为1”!
输入 | 运算符 | 输入 | 结果 |
---|---|---|---|
1 | ⊕ | 0 | 1 |
1 | ⊕ | 1 | 0 |
0 | ⊕ | 0 | 0 |
0 | ⊕ | 1 | 1 |
若需要交换两个变量的值,除了通常使用的借用中间变量进行交换外,还可以利用异或,仅使用两个变量进行交换,如:
a=a^b;
b=b^a;
a=a^b;
详解:
a1=a^b
b=a1^b
a=a1^b=a1^(a1^b)=a1^a1^b=b