leetcode136-寻找数组中仅出现一次的数字


文章首发于taskhub

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
}

posted @ 2020-09-02 09:36  litchi99  阅读(143)  评论(0编辑  收藏  举报