📜  谜题77 |更好的选择(1)

📅  最后修改于: 2023-12-03 15:12:12.439000             🧑  作者: Mango

谜题77 | 更好的选择

题目描述

有一个集合 S,其中存放了 n 个互异的元素,并以数组的形式呈现。我们需要从中选择两个元素 e1e2 并计算它们的和 s,并保证这个和不在集合 S 中。

请你写一个函数 better_choice(S: List[int]) -> Tuple[int, int] 返回任意一组(e1, e2)满足题目要求。如果无解,则返回 None

限制条件:

  • $2 \leq n \leq 10^4$
  • $-10^9 \leq S_i \leq 10^9$
解题思路

如果需要找到两个元素的和不在集合中,我们可以用如下算法:

  1. 对于集合 S 中的每个元素 i,把 $k-s$ 添加到一个新的集合 S' 中,其中 $k$ 是 i 的值,$s$ 是 S 中的另一个元素的值。这样就可以构造一个新的集合,其中包含了每个元素对的和。

  2. 然后,我们遍历 S 中的元素 $i$,并在 S' 中查找 $k'-i$,其中 $k'$ 是 i 的值。如果找到了这个值,那么这个元素对就不是一个好的选择。

  3. 如果没有找到这个元素对,那么这个元素对就是一个好的选择。

因为我们需要将两个集合按照值排序,以便我们可以用 O(n) 的时间复杂度在它们中查找元素对。这意味着总的时间复杂度为 O(n log n)。因此,我们可以把这个算法实现为一个函数,如下所示:

from typing import List, Tuple

def better_choice(S: List[int]) -> Tuple[int, int]:
    n = len(S)
    S_pairs = []  # 存放元组的和
    for i in range(n):
        for j in range(i + 1, n):
            S_pairs.append((S[i] + S[j], i, j))
    S_pairs.sort()  # 按照和来排序
    for k in range(n):
        for l in range(k + 1, n):
            s = S[k] + S[l]
            # 用二分查找在 S_pairs 中找到 s
            i = bisect_left(S_pairs, (s, -1, -1))
            if i == len(S_pairs) or S_pairs[i][0] != s:
                # 如果没有找到,直接返回
                return S[k], S[l]
    return None
总结

借助集合中元素对之和的新集合,我们可以很方便地解决这个问题。由于需要将两个集合按照值排序,因此总的时间复杂度为 O(n log n)。如果原始集合是已经排好序的,那么这个算法的性能会更好。

此外,这个问题也可以使用哈希表实现。在这种方法中,我们首先将所有的元素添加到一个哈希表中,然后对于集合中的每个元素 $i$,我们可以使用 $k-i$ 的补码来查找哈希表,其中 $k$ 是我们正在考虑的元素。如果哈希表中没有这个值,则 $i$ 和 $k$ 组成一个好的选择。如果集合中有相同的元素,那么哈希表中也必须有它们的对应项。如果没有对应项,可能会导致无效的选择。