📅  最后修改于: 2023-12-03 14:58:24.907000             🧑  作者: Mango
给定 $n$ 个整数的集合 $S$ 和一个定值 $T$,请在 $S$ 中找出一些数字,使得这些数字的和恰好为 $T$。
第一行包含整数 $n$ 和 $T$。
第二行包含 $n$ 个不同的数字,每个数字之间用空格隔开。
按从小到大的顺序输出所求的子集中的数字,数字之间用空格隔开。如果有多解,请输出任意一个。如果无解,则输出 No Solution
。
输入:
9 100
75 34 56 12 77 40 98 23 45
输出:
23 34 43
题目要求求解集合 $S$ 中和为 $T$ 的子集,这种问题称为子集和问题(Subset Sum Problem)。
只考虑和为 $T$ 的子集数量有多少种,可以使用动态规划求解。
设 $f(i, j)$ 表示只考虑前 $i$ 个数,且和恰好为 $j$ 的方案数。则有:
$$ f(i, j) = \begin{cases} 1, & j=0 \ 0, & i=0 \ f(i-1, j) + f(i-1, j-s_i), & j\ge s_i \ f(i-1, j), & j<s_i \end{cases} $$
其中 $s_i$ 表示第 $i$ 个数字。
动态规划求解可以优化成空间复杂度为 $O(T)$ 的形式。
def subset_sum(n: int, T: int, S: List[int]) -> List[int]:
f = [0] * (T + 1)
f[0] = 1
for i in range(1, n + 1):
for j in range(T, S[i - 1] - 1, -1):
f[j] += f[j - S[i - 1]]
if f[T]:
res = []
j = T
for i in range(n, 0, -1):
if j >= S[i - 1] and f[j - S[i - 1]]:
res.append(S[i - 1])
j -= S[i - 1]
return res[::-1]
else:
return ['No Solution']
时间复杂度:$O(NT)$,其中 $N$ 是数字的个数,$T$ 是目标和。