Description
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
Analyze
给定的函数如下:
- @param nums 一个整数数组
- @param numsSize 数组长度
- @return 只出现一次的数字
这题乍一看可以暴力解,即把每一个数都跟其他的数对比,如果有相同的就下一个,如果没有就直接返回这个数,实际上也确实可以,但是因为要把每一个数都跟其他的数对比,时间复杂度就比较高了,有一种比较快的方法是用位运算来解决。
题中数字都出现了两次,只有一个出现了一次,而在位操作中有一个 "异或" 操作可以把相同的数给去掉,具体如下:
"异或",在C语言中用 ^ (shift + 6)表示,异或是位运算的一种,表示把两个数字 "按位异或",即把两个数转换为二进制,然后分别对每一位做异或操作,相同为0,不同为1,比如12 ^ 5:
3 2 1 0 1 1 0 0 0 1 0 1 1 0 0 1 最后结果为1001,转换为10进制就是9,这是异或的基本运算。既然异或是相同为0,不同为1,那么显然可以得出几个性质:
- 任何数跟自己异或都等于 0
- 任何数跟 0 异或都等于原来的数
并且异或满足交换律,即12 ^ 5 ^ 12 与 12 ^ 12 ^ 5 的答案是一样的,因为他们都是转换成二进制来计算的,因此某一位是 0 ^ 1 ^ 0 或者 0 ^ 0 ^ 1都是一样的,这三个数不会改变。
回到题目,显然如果把数组中的所有数都进行一次异或操作,那些出现了两次的数字都会变成0,而目标数字在最后会被保留。
Realization
- 特殊情况处理
如果只有一个数字那么直接返回
-
循环
-
返回
-
提交
Dictionary
位运算对于程序效率的提高是很有帮助的,因为数字在计算机中本就是以二进制方式保存的,因此使用位运算可以明显的提高效率。对于这个题,其实这个解法不仅仅是针对这个题,与之类似的其他题都是这样解,比如题目改成所有数字出现偶数次,只有一个数字出现奇数次,那么这题的解法甚至是代码都是一样的。因此灵活使用位运算对解题还有实际开发都很有帮助。
附源代码
int singleNumber(int* nums, int numsSize){
if(numsSize == 1)return nums[0];
int result = nums[0];
for(int i = 1; i < numsSize; ++i)
{
result = result^nums[i];
}
return result;
}