📅  最后修改于: 2023-12-03 15:12:12.439000             🧑  作者: Mango
有一个集合 S
,其中存放了 n
个互异的元素,并以数组的形式呈现。我们需要从中选择两个元素 e1
和 e2
并计算它们的和 s
,并保证这个和不在集合 S
中。
请你写一个函数 better_choice(S: List[int]) -> Tuple[int, int]
返回任意一组(e1, e2)满足题目要求。如果无解,则返回 None
。
限制条件:
如果需要找到两个元素的和不在集合中,我们可以用如下算法:
对于集合 S
中的每个元素 i
,把 $k-s$ 添加到一个新的集合 S'
中,其中 $k$ 是 i
的值,$s$ 是 S
中的另一个元素的值。这样就可以构造一个新的集合,其中包含了每个元素对的和。
然后,我们遍历 S
中的元素 $i$,并在 S'
中查找 $k'-i$,其中 $k'$ 是 i
的值。如果找到了这个值,那么这个元素对就不是一个好的选择。
如果没有找到这个元素对,那么这个元素对就是一个好的选择。
因为我们需要将两个集合按照值排序,以便我们可以用 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$ 组成一个好的选择。如果集合中有相同的元素,那么哈希表中也必须有它们的对应项。如果没有对应项,可能会导致无效的选择。