题目:
给你一个仅由整数组成的有序数组,其中每个元素都会出现两次,唯有一个数只会出现一次。
请你找出并返回只出现一次的那个数。
你设计的解决方案必须满足 O(log n) 时间复杂度和 O(1) 空间复杂度。
示例 1:
输入: nums = [1,1,2,3,3,4,4,8,8]
输出: 2
示例 2:
输入: nums = [3,3,7,7,10,11,11]
输出: 10
提示:
1 <= nums.length <= 105
0 <= nums[i] <= 105
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/single-element-in-a-sorted-array
解题思路:
采用按位异或运算的规律进行此题的解析。
先介绍一下按位异或运算:
参加运算的两个数据,按二进制位进行“异或”运算。
参加运算的两个对象,如果两个相应位为“异”(值不同),则该位结果为1,否则为0。
“异或运算”的特殊作用:
(1)使特定位翻转找一个数,对应X要翻转的各位,该数的对应位为1,其余位为零,此数与X对应位异或即可。
例:X=10101110,使X低4位翻转,用X ^ 0000 1111 = 1010 0001即可得到。
(2)与0相异或,保留原值 ,X ^ 00000000 = 1010 1110。
下面重点说一下按位异或,异或其实就是不进位加法,如1+1=0,,0+0=0,1+0=1。
异或的几条性质:
1、交换律
2、结合律(即(a ^ b) ^ c == a ^ (b ^ c))
3、对于任何数x,都有x ^ x=0,x ^ 0=x
4、自反性: a ^ b ^ b = a ^ 0 = a;
应用举例:
1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现
一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空
间,能否设计一个算法实现?
解法一、显然已经有人提出了一个比较精彩的解法,将所有数加起来,减去1+2+…+1000的和。
这个算法已经足够完美了,相信出题者的标准答案也就是这个算法,唯一的问题是,如果数列过大,则可能会导致溢出。
解法二、异或就没有这个问题,并且性能更好。
将所有的数全部异或,得到的结果与1^ 2 ^ 3 ^ … ^ 1000的结果进行异或,得到的结果就是重复数。
代码(与解法二同理)
class Solution {
public:
int singleNonDuplicate(vector<int>& nums) {
for(int i = 0; i < nums.size() - 1; i++){nums[i + 1] ^= nums[i];}
return nums.back();
}
};
作者:yi-si-cb
链接:https://leetcode-cn.com/problems/single-element-in-a-sorted-array/solution/xie-shi-an-wei-yi-huo-c-by-yi-si-cb-ab3a/