题目

题目:给定一个整数列表 nums 和一个整数 target,请使用哈希表找出列表中两个数的下标,使得这两个数之和等于 target。假设每个输入都有且仅有一个解决方案,且不能使用同一个元素两次。

示例:

输入:

nums = [2, 7, 11, 15]
target = 9

输出:

[0, 1]

解释:因为 nums[0] + nums[1] = 2 + 7 = 9,所以答案是 [0, 1]
请实现一个函数 two_sum,接收 nums 和 target 作为输入参数,返回满足条件的下标列表。

def two_sum(nums, target):
    # 在这里编写您的代码
    pass

提示:考虑使用字典(Python 中的哈希表实现)来存储已经遍历过的元素及其下标。这样,在遍历列表时,可以快速查找哈希表中是否存在一个值,使得当前元素和这个值之和等于 target

答案

def two_sum(nums, target):
    hash_table = {}  # 创建一个空字典用于存储已遍历过的元素及其下标
    
    for i, num in enumerate(nums):  # 遍历整数列表及其下标
        complement = target - num  # 计算目标值与当前元素的差值
        
        # 检查差值是否已经在哈希表中
        if complement in hash_table:
            # 如果找到了匹配的组合,返回差值的下标和当前元素的下标
            return [hash_table[complement], i]
        
        # 如果差值不在哈希表中,将当前元素及其下标添加到哈希表
        hash_table[num] = i
        
    return None  # 如果没有找到匹配的组合,返回 None

现在我们可以测试这个函数:

nums = [2, 7, 11, 15]
target = 9
result = two_sum(nums, target)
print(result)  # 输出: [0, 1]

在这个实现中,我们遍历输入的整数列表 nums。对于每一个元素 num,我们计算 target 减去 num 的差值 complement。
然后,我们检查哈希表 hash_table 是否已经包含了这个差值。如果包含,说明我们找到了一个匹配的组合,返回差值的下标和当前元素的下标。如果不包含,我们将当前元素 num 及其下标 i 添加到哈希表中。这样,在遍历过程中,我们可以快速地查找哈希表中是否存在满足条件的值。
下面是带留学生实现的字典,如何解决这道题目呢?

# Python 实现二次探测,需要如下内容:
# 1. 原理解析
# 2. 特点
# 3. 实现代码
# 4. 代码详细注释
# 5. 代码测试
# 6. 应用场景

"""
二次探测(Quadratic Probing)是一种开放寻址法(Open Addressing)的哈希表(Hash Table)解决冲突的方法。
当插入一个新的键值对时,如果发生冲突,二次探测会沿着二次探测序列查找下一个可用的哈希表索引。
具体地说,当第 i 次冲突发生时,二次探测会尝试在 (hash(key) + i^2) % table_size 的位置进行插入或查找。

特点:
二次探测可以解决哈希表的冲突问题
对于较小的负载因子,二次探测性能较好
相比于线性探测,二次探测可以更好的避免聚簇现象
"""

class QuadraticProbingHashTable:
    def __init__(self, size=11):
        self.size = size  # 设置哈希表大小
        self.slots = [None] * self.size  # 初始化哈希表的键槽
        self.data = [None] * self.size  # 初始化哈希表的值槽

    def put(self, key, value):
        hash_value = self.hash_function(key)  # 计算键的哈希值

        # 如果槽为空,插入键值对
        if self.slots[hash_value] is None:
            self.slots[hash_value] = key
            self.data[hash_value] = value
        else:
            # 如果槽已被占用,且键相同,则更新值
            if self.slots[hash_value] == key:
                self.data[hash_value] = value
            else:
                # 如果槽已被占用,键不同,则进行二次探测
                i = 1
                next_slot = self.rehash(hash_value, i)
                while self.slots[next_slot] is not None and self.slots[next_slot] != key:
                    i += 1
                    next_slot = self.rehash(hash_value, i)

                # 如果找到空槽或者相同的键,则插入或更新键值对
                if self.slots[next_slot] is None:
                    self.slots[next_slot] = key
                    self.data[next_slot] = value
                else:
                    self.data[next_slot] = value

    def hash_function(self, key):
        return key % self.size  # 计算哈希值的简单方法

    def rehash(self, old_hash, i):
        return (old_hash + i ** 2) % self.size  # 二次探测的哈希重新计算

    def get(self, key):
        start_slot = self.hash_function(key)  # 计算键的哈希值
        position = start_slot
        found = False
        stop = False
        i = 1

        # 遍历哈希表,直到找到键或遍历完所有槽
        while self.slots[position] is not None and not found and not stop:
            if self.slots[position] == key:  # 如果找到键,返回对应的值
                found = True
                return self.data[position]
            else:
                position = self.rehash(start_slot, i)  # 二次探测寻找下一个槽
                i += 1
                if position == start_slot:  # 如果回到起始槽,停止遍历
                    stop = True

        return None  # 如果未找到键,返回 None

    # 重载字典访问和赋值操作符
    def __getitem__(self, key):
        return self.get(key)

    def __setitem__(self, key, value):
        self.put(key, value)


ht = QuadraticProbingHashTable()
ht[54] = "cat"
ht[26] = "dog"
ht[93] = "lion"
ht[17] = "tiger"
ht[77] = "bird"
ht[31] = "cow"
ht[44] = "goat"
ht[55] = "pig"
ht[20] = "chicken"

# 输出哈希表的键槽和值槽
print("Slots: ", ht.slots)
print("Data: ", ht.data)

# 从哈希表中获取键对应的值
print("Value for key 20: ", ht[20])  # 输出: Value for key 20:  chicken

# 更新哈希表中的键值对
ht[20] = "duck"

# 输出更新后的哈希表的键槽和值槽
print("Updated slots: ", ht.slots)
print("Updated data: ", ht.data)

# 从哈希表中获取更新后的键对应的值
print("Updated value for key 20: ", ht[20])  # 输出: Updated value for key 20:  duck

以下是使用二次探测哈希表实现的 two_sum 函数:

def two_sum(nums, target):
    hash_table = QuadraticProbingHashTable()  # 创建一个二次探测哈希表实例
    
    for i, num in enumerate(nums):  # 遍历整数列表及其下标
        complement = target - num  # 计算目标值与当前元素的差值
        
        # 检查差值是否已经在哈希表中
        if hash_table.get(complement) is not None:
            # 如果找到了匹配的组合,返回差值的下标和当前元素的下标
            return [hash_table[complement], i]
        
        # 如果差值不在哈希表中,将当前元素及其下标添加到哈希表
        hash_table[num] = i
        
    return None  # 如果没有找到匹配的组合,返回 None

这个实现与之前的实现非常相似,但是在这里我们使用 QuadraticProbingHashTable 类来代替字典。我们使用 get 方法来检查哈希表中是否存在差值 complement,如果存在,则返回差值的下标和当前元素的下标。如果不存在,我们将当前元素 num 及其下标 i 添加到哈希表中。这种实现方式同样可以在遍历过程中快速查找满足条件的值。

更多推荐