青训营X豆包MarsCode刷题之找单独的数 | 豆包MarsCode AI刷题

57 阅读3分钟

找单独的数 题目解析记录

原题目如下:

问题描述

在一个班级中,每位同学都拿到了一张卡片,上面有一个整数。有趣的是,除了一个数字之外,所有的数字都恰好出现了两次。现在需要你帮助班长小C快速找到那个拿了独特数字卡片的同学手上的数字是什么。

要求:

  1. 设计一个算法,使其时间复杂度为 O(n),其中 n 是班级的人数。
  2. 尽量减少额外空间的使用,以体现你的算法优化能力。

测试样例

样例1:

输入:cards = [1, 1, 2, 2, 3, 3, 4, 5, 5]
输出:4
解释:拿到数字 4 的同学是唯一一个没有配对的。

样例2:

输入:cards = [0, 1, 0, 1, 2]
输出:2
解释:数字 2 只出现一次,是独特的卡片。

样例3:

输入:cards = [7, 3, 3, 7, 10]
输出:10
解释:10 是班级中唯一一个不重复的数字卡片。

约束条件

  • 1 ≤ cards.length ≤ 1001
  • 0 ≤ cards[i] ≤ 1000
  • 班级人数为奇数
  • 除了一个数字卡片只出现一次外,其余每个数字卡片都恰好出现两次

思路分享

首先这道题目还是比较简单的。题目要求时间复杂度为O(n),并且需要统计数字重复的次数,第一反应就想到了使用哈希表的数据结构。

哈希表

哈希表是根据关键码的值而直接进行访问的数据结构。数组就是一张哈希表。 image.png 一般哈希表可以用来快速判断一个元素是否出现在集合里。

Go语言中常用的哈希结构为Map。针对该题目,创建一个map[int]int类型,遍历cards数组,key值为card的数值,value值为出现的次数,遍历该数组的时间复杂度为O(n)。之后访问该map,查询map的时间复杂度为O(1),如果出现value值为1的元素,说明该元素为满足要求的数字。 Go语言实现代码如下:

package main

import "fmt"

func solution(cards []int) int {
    countMap := make(map[int]int)
    
    for _, card := range cards {
        countMap[card]++
    }
    
    for card, count := range countMap {
        if count == 1 {
            return card
        }
    }
    
    return -1
}

func main() {
	// Add your test cases here

	fmt.Println(solution([]int{1, 1, 2, 2, 3, 3, 4, 5, 5}) == 4)
	fmt.Println(solution([]int{0, 1, 0, 1, 2}) == 2)
}

运行代码即可成功。

异或运算思路

使用MarsCode AI 中需要一点思路提示的功能,AI给了一种我没有想到的思路,即使用异或运算。使用异或运算的时间复杂度为O(n),但可以大大降低空间复杂度。 代码如下:

func solution(cards []int) int {
    result := 0
    for _, card := range cards {
        result ^= card // 使用异或运算
    }
    return result
}

可以看到代码十分简洁。这得益于异或运算的性质。

  • 任何数与自身异或的结果是0
  • 任何数与0异或的结果是它自身
  • 异或运算满足交换律和结合律

暴力运算

使用暴力运算当然也可以解决本题,即先对数组进行排序,然后遍历数组找到唯一一个不重复的数字。但是该算法的时间复杂度为O(n log n),不符合题目要求了,这里仅提供一种思路。参考代码如下:

import "sort"

func solution(cards []int) int {
    sort.Ints(cards)
    for i := 0; i < len(cards); i += 2 {
        if i == len(cards)-1 || cards[i] != cards[i+1] {
            return cards[i]
        }
    }
    return -1
}

总结

检查重复元素有暴力运算、异或运算和哈希表三种可用的方式。 异或运算适合检查是否出现偶数次,而哈希表则可以检查出具体出现多少次,功能更强,但空间复杂度更高。