这个还是有点难搞,许久不曾写算法了,还是有点慢了,持续了半个小时左右,并且使用了goland调式
解
package main
func singleNumber(nums []int) []int {
if len(nums) == 0 {
return []int{}
}
var mid int
for _, v := range nums {
mid ^= v
}
// 获取非0的第一位
singleNum := mid & (^mid + 1)
if singleNum == 0 {
return []int{mid}
}
// 分成两组
var r1, r2 int
for _, v := range nums {
if singleNum&v != 0 {
r1 ^= v
} else {
r2 ^= v
}
}
return []int{r1, r2}
}
思路
验证只出现一次的两个数字,首先还是使用异或的方法,先获取唯一的数,此时的这个数是两个目标数的异或,因为其他数都出现了两次,这个也很好理解是吧。
接着就是怎么把这些数分开的问题了,方法也很简单,使用上一步得出的结果,从低位到高位,找到第一个非0的位(先叫它非0位数),这意味着什么,这意味着原始数字可以在非0位数下,分成两组,巧妙,巧妙,大家细细品,看看是不是这样。
最后,对每组数进行分别异或,就可以得出来那两个只出现一次的数了。
中间有个小点,我觉得是值得拿出来说说的,就是如何获取非0位数,这个获取的方法有很多。我可以想到的有两种
- 遍历 这个需要注意边界
- 计算 这个就是让我很欣喜若狂的点singleNum := mid & (^mid + 1)
显然,在计算方式下,可以直接获取到我们的非0位数
网友评论