Swift 数据结构与算法(35) + Leetcode170. 两数之和 III - 数据结构设计(哈希)

77 阅读5分钟

Swift 数据结构与算法( ) + Leetcode 掘金 #日新计划更文活动

题目

170. 两数之和 III - 数据结构设计

设计一个接收整数流的数据结构,该数据结构支持检查是否存在两数之和等于特定值。

实现 TwoSum 类:

  • TwoSum() 使用空数组初始化 TwoSum 对象
  • void add(int number) 向数据结构添加一个数 number
  • boolean find(int value) 寻找数据结构中是否存在一对整数,使得两数之和与给定的值相等。如果存在,返回 true ;否则,返回 false 。

 

示例:

输入:
["TwoSum", "add", "add", "add", "find", "find"]
[[], [1], [3], [5], [4], [7]]
输出:
[null, null, null, null, true, false]

解释:
TwoSum twoSum = new TwoSum();
twoSum.add(1);   // [] --> [1]
twoSum.add(3);   // [1] --> [1,3]
twoSum.add(5);   // [1,3] --> [1,3,5]
twoSum.find(4);  // 1 + 3 = 4,返回 true
twoSum.find(7);  // 没有两个整数加起来等于 7 ,返回 false

 

提示:

  • -105 <= number <= 105
  • -231 <= value <= 231 - 1
  • 最多调用 104 次 add 和 find
class TwoSum {

    init() {

    }
    
    func add(_ number: Int) {

    }
    
    func find(_ value: Int) -> Bool {

    }
}

解题思路🙋🏻‍ ♀️

在遍历 numbers 字典时,当我们遇到一个 key,并且发现 complement == key,这意味着我们已经找到了两个值:正在遍历的 keycomplement。但事实上,这两个值都是同一个值。

举一个具体的例子来解释:

假设 numbers 字典如下:

numbers = [2:1, 3:1, 4:1, ...]

这意味着数字 2、3 和 4 分别在数据结构中出现了 1 次。

现在,假设我们想找两数之和为 4。当我们遍历到数字 2 时,complement 就会被计算为 2(因为 (4 - 2 = 2))。此时,complementkey 都是 2。但我们不能说我们找到了两个数字 2,因为 numbers 字典告诉我们 2 只出现了一次。

所以,当 complement == key 时,我们必须检查数字 2(在这个例子中)是否至少出现了两次(即 count > 1),因为我们需要两个数字 2 来形成所需的和。如果 count 仅为 1,这意味着我们只有一个数字 2,这不足以形成所需的和。但如果 count > 1,这意味着我们至少有两个数字 2,所以我们可以确认找到了一个有效的配对。

边界思考🤔

代码

class TwoSum {
    
    // 使用哈希表存储每个数字以及它出现的次数
    private var numbers: [Int: Int] = [:]

    // 初始化函数
    init() {}
    
    // 添加一个数字到数据结构中
    func add(_ number: Int) {
        if let count = numbers[number] {
            numbers[number] = count + 1
        } else {
            numbers[number] = 1
        }
    }
    
    // 查找是否存在两个数字之和为特定值
    func find(_ value: Int) -> Bool {
        for (num, count) in numbers {
            let complement = value - num
            if complement == num {
                // 如果两个数字相同,确保至少有两个这样的数字
                if count > 1 {
                    return true
                }
            } else if numbers[complement] != nil {
                return true
            }
        }
        return false
    }
}

时空复杂度分析

O (n)

错误与反思

首先,complement 是我们要在数据结构中查找的数,其值是 value - key,其中 value 是我们想要检查的两数之和,key 是我们当前正在遍历的数字。

现在,考虑以下两种情况:

情况1:complement 和 key 是不同的数

如果 complementkey 是不同的数字,那么我们只需要检查 complement 是否在数据结构中即可。例如,如果我们有数字 [1, 3, 5] 并且我们要查找的值是 4,那么当我们遍历到 1 时,complement 将是 3。我们只需要检查数字 3 是否在数据结构中即可。

情况2:complement 和 key 是相同的数

这是上述代码部分处理的情况。假设我们有数字 [2, 2, 3, 4] 并且我们要查找的值是 4。当我们遍历到第一个 2 时,complement 也是 2。在这种情况下,我们不能只因为数据结构中有一个 2 就立即返回 true,因为这样我们就只有一个 2,不能形成两数之和为 4

但是,如果我们在数据结构中有两个 2,那么我们可以返回 true。这就是为什么我们检查 count > 1 的原因。如果 count 大于 1,这意味着我们有两个或更多的 key(在这个例子中是 2),因此我们可以形成两数之和为 value

总之,这部分代码确保了当我们需要两个相同的数字来形成所需的和时,数据结构中确实有两个这样的数字。

概念

使用场景与应用

  1. 哈希映射(Hash Map):在这题中,我们使用字典(在 Swift 中为 Dictionary)来存储每个数字及其出现的次数。哈希映射提供了常数时间的查找、添加和删除操作,这使我们能够快速检查一个数的存在,并知道它出现的次数。

  2. 查找补数(Complement):为了找到两数之和,我们常常需要查找一个数的补数。例如,如果我们想要找出两个数的和是否为 x,并且我们已经有一个数 y,那么我们需要查找 x - y

  3. 处理重复值:在很多算法题中,处理重复值都是一个关键和复杂的步骤。在这题中,我们需要确保在计算两数之和时,我们考虑到了数字的实际出现次数。

实际应用场景及技术点:

  1. 购物网站推荐系统:当用户查看一个商品时,系统可能会推荐其他商品与当前商品组合购买以达到某种优惠。这需要快速查找哪些商品组合可以达到优惠条件。技术点:哈希映射可以快速查找补数。

  2. 财务软件:在处理大量的交易数据时,可能需要查找哪两笔交易的总和等于一个特定的金额。技术点:使用哈希映射来存储每笔交易的金额和出现的次数,并快速查找其补数。

iOS app 开发的实际使用场景:

  1. 社交应用中的“你可能认识的人”功能:应用需要在用户的好友列表中快速找到与当前用户有多个共同好友的用户。技术应用:使用哈希映射存储每个用户的好友列表,快速查找共同好友。

  2. 音乐或视频播放应用:当用户播放一个歌曲或视频时,应用可能会推荐与当前播放内容相似的其他内容。技术应用:哈希映射可以快速查找与当前内容标签或特征相匹配的其他内容。