算法:寻找单独的数,算法问题解决示例

35 阅读4分钟

问题描述

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

要求:

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

问题分析

在一个班级中,每位同学都持有一个卡片,上面有一个整数。除一个数字外,所有的数字都恰好出现两次。我们需要在 O(n) 的时间复杂度内找出那个唯一出现一次的数字。并且要求尽量减少额外空间的使用。根据给定的条件,班级人数为奇数,除了一个数字外其他数字都出现了两次。

解决思路

根据题目的要求,我们需要在 O(n) 时间内找到唯一的数字,并且空间复杂度需要控制在 O(1)(即不使用额外的空间)。这提示我们可以使用 异或(XOR)运算 来解决这个问题。

异或运算的性质
  1. 交换律a ^ b = b ^ a
  2. 结合律(a ^ b) ^ c = a ^ (b ^ c)
  3. 任何数与0异或,结果是数本身a ^ 0 = a
  4. 任何数与自身异或,结果是0a ^ a = 0

利用上述性质,假设我们对所有数字进行异或操作,因为相同的数字会互相抵消(即 a ^ a = 0),所以最终剩下的结果就是那个唯一出现一次的数字。

步骤
  1. 初始化一个变量 result 为 0。
  2. 遍历所有卡片上的数字,对 result 进行异或操作。
  3. 最后,result 的值就是唯一的那个数字。

时间复杂度和空间复杂度

  • 时间复杂度:每个数字都参与一次异或操作,因此时间复杂度是 O(n),其中 n 是卡片的数量。
  • 空间复杂度:我们只使用了一个额外的变量 result,因此空间复杂度是 O(1)。

Golang 代码实现

package main

import "fmt"

func findUniqueNumber(cards []int) int {
    result := 0
    for _, card := range cards {
        result ^= card
    }
    return result
}

func main() {
    cards1 := []int{1, 1, 2, 2, 3, 3, 4, 5, 5}
    cards2 := []int{0, 1, 0, 1, 2}
    cards3 := []int{7, 3, 3, 7, 10}
    
    fmt.Println("Unique number in cards1:", findUniqueNumber(cards1)) // 输出:4
    fmt.Println("Unique number in cards2:", findUniqueNumber(cards2)) // 输出:2
    fmt.Println("Unique number in cards3:", findUniqueNumber(cards3)) // 输出:10
}

代码解析

  1. findUniqueNumber(cards []int):该函数遍历卡片数字数组,通过异或操作得到唯一的数字。
  2. 主函数 main() 中,测试了多个样例,分别输出唯一数字。

测试样例

  1. 输入:cards = [1, 1, 2, 2, 3, 3, 4, 5, 5] 输出:4
  2. 输入:cards = [0, 1, 0, 1, 2] 输出:2
  3. 输入:cards = [7, 3, 3, 7, 10] 输出:10

UML 设计

在算法实现中,我们可以使用 UML 绘制 活动图(Activity Diagram) 来表示算法的执行流程。

Activity Diagram (活动图)

活动图用于表示算法的执行过程,我们可以通过以下步骤来展示该算法:

  • 初始化一个 result = 0
  • 遍历每一个卡片数字并对 result 进行异或操作。
  • 最后返回 result

image.png

解释:

  • StartEnd 标识了活动图的开始和结束。
  • Initialize result = 0 表示初始化操作。
  • For each card in cards 是一个循环,每次从卡片列表中取出一个数字进行异或运算。
  • 最后返回 result,这个结果就是唯一的数字。

通过这个活动图,我们能够直观地理解异或算法的执行流程。


总结

通过本题的求解,我们展示了如何利用异或运算快速地找到唯一的数字。该算法在时间复杂度和空间复杂度上均得到了优化,符合 O(n) 时间复杂度和 O(1) 空间复杂度的要求。通过 UML 活动图,我们可以清晰地表示出该算法的流程,帮助更好地理解和学习该算法。