leetcode136-寻找数组中仅出现一次的数字
1. 仅出现一次与均出现两次
题目描述:在给定的非空数组中,仅有一个数字出现一次,其余数字均出现两次,如[1,2,2,3,3]或[1,1,2,3,3]
解题思路:1)分类讨论,利用数组特性;2)利用异或XOR的特性
1.1 分类讨论法
- 当切片长度为1时,直接返回
- 当排序后的切片前两位数字不相等时,直接返回
- 当排序后的切片前两位数字相等时,从第0位元素开始每次取两个相邻的元素,判断两者是否相等,若不等则可知元素组合的第一个元素即为仅出现一次的元素
- 该方法不需要占用额外的内存空间,时间复杂度为o(n)
// golang实现
func singleNumber(nums []int) int {
//对切片进行排序
sort.Ints(nums)
// 排除长度为1的情况
// 当前两位数字相同时,即[1,1,2,2,3]或[1,1,2,3,3]等情况,只需比较对应位置的相邻两数是否相等
if len(nums)!=1 && nums[0] == nums[1]{
// 遍历第0,2,4...组数字,当某组数字不相等时,则第i个数即为出现一次的数字
// 由题意可知,数组长度为奇数,因此i只能遍历到倒数三个数,否则将溢出
for i:=0;i<len(nums)-2;i+=2{
if nums[i] != nums[i+1]{
return nums[i]
}
}
// 当两两组合均相等时,数组最后一位元素即为仅出现一次的数字
return nums[len(nums)-1]
}else{
return nums[0]
}
1.2 异或位运算
- 任意数与0进行异或,其结果为该数本身,0 XOR a = a
- 两个相同的数进行异或,其结果为0, a XOR a = 0
- 使用异或方法不需要对数组进行排序
// golang实现
func singleNumber(nums []int) int {
single := 0
for _, num := range nums {
single ^= num
}
return single
}
2. 仅出现一次与均出现三次
2.1 分类讨论法
- 分类讨论法与1.1类似,将两两比较组合更改为每三个元素一组
- 需要注意数组遍历的边界
// golang实现
func singleNumber(nums []int) int {
sort.Ints(nums)
if len(nums)!=1 && nums[0] == nums[1] && nums[1]==nums[2]{
for i:=1;i<len(nums)-2;i+=3{
if nums[i-1] != nums[i]{
return nums[i-1]
}
}
return nums[len(nums)-1]
}else{
return nums[0]
}
}
2.2 位运算组合
- 由于异或结果无法区分出现1次和出现3次等奇数个元素的情况,需要使用两个位掩模对异或结果进行处理
- seenOnce记录出现一次的数字,seenTwice记录出现两次的数字
- 异或法参考官方题解leetcode
// golang实现
func singleNumber(nums []int) int {
var seenOnce,seenTwice = 0,0
for _,num := range nums{
seenOnce = ^seenTwice & (seenOnce ^ num)
seenTwice = ^seenOnce & (seenTwice ^ num)
}
return seenOnce
}