📅  最后修改于: 2023-12-03 15:25:40.283000             🧑  作者: Mango
对于给定的数组和整数 X,找出数组中有多少个子集的和为 X。
给定一个整数数组 nums 和一个目标值 X,找出数组中和等于 X 的子集的个数。
示例:
输入:nums = [1,2,3,4,5], X = 7 输出:2 解释:[3,4] 和 [2,5] 是和等于 7 的两个子集。
使用动态规划,令 dp[i][j] 表示从数组的前 i 个元素中选取一些元素,使它们的和等于 j 的方案数。
当不选取 nums[i] 时,dp[i][j] = dp[i-1][j]。 当选取 nums[i] 时,dp[i][j] += dp[i-1][j-nums[i]]。 所以方程为:dp[i][j] = dp[i-1][j] + dp[i-1][j-nums[i]]。
原因:dp[i][j] 表示的是前 i 个元素中选取若干个元素和为 j 的方案数,那么 dp[i-1][j] 表示的就是不选取第 i 个元素,从前 i-1 个元素中选取若干个元素和为 j 的方案数。dp[i-1][j-nums[i]] 表示的就是选取了第 i 个元素,那么从前 i-1 个元素中选取若干个元素和为 j-nums[i] 的方案数。
最后 dp[n][X] 即为答案。
使用递归,从数组的最后一个元素开始向前搜索,每次递归分别传入当前元素的值和剩余的目标值。每次搜索到和为目标值的时候,计数器加 1。
def count_subsets(nums, X):
n = len(nums)
dp = [[0] * (X+1) for _ in range(n+1)]
for i in range(n+1):
dp[i][0] = 1
for i in range(1, n+1):
for j in range(1, X+1):
if j >= nums[i-1]:
dp[i][j] = dp[i-1][j] + dp[i-1][j-nums[i-1]]
else:
dp[i][j] = dp[i-1][j]
return dp[n][X]
def count_subsets(nums, X):
count = [0] # 计数器
def dfs(cur, target):
if target == 0: # 搜索到和为目标值
count[0] += 1
return
if cur == -1: # 没有任何元素了
return
if nums[cur] > target: # 当前元素大于目标值,不能选
dfs(cur-1, target)
return
dfs(cur-1, target) # 不选当前元素
dfs(cur-1, target-nums[cur]) # 选当前元素
dfs(len(nums)-1, X)
return count[0]
此题可以使用动态规划或者递归来解决,动态规划比较直观而递归思路更为清晰。使用动态规划的时间复杂度是 O(nX),使用递归的时间复杂度是 O(2^n),因此使用动态规划更加高效。