动态规划 - 377. 组合总和 Ⅳ

107 阅读2分钟

4月日新计划更文活动 第16天

前言

动态规划专题,从简到难通关动态规划。

每日一题

今天的题目是 377. 组合总和 Ⅳ,难度为中等

给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。

题目数据保证答案符合 32 位整数范围。

示例 1:

输入: nums = [1,2,3], target = 4 输出: 7 解释: 所有可能的组合为: (1, 1, 1, 1) (1, 1, 2) (1, 2, 1) (1, 3) (2, 1, 1) (2, 2) (3, 1) 请注意,顺序不同的序列被视作不同的组合。

示例 2:

输入: nums = [9], target = 3 输出: 0

提示:

  • 1 <= nums.length <= 200
  • 1 <= nums[i] <= 1000
  • nums 中的所有元素 互不相同
  • 1 <= target <= 1000

进阶: 如果给定的数组中含有负数会发生什么?问题会产生何种变化?如果允许负数出现,需要向题目中添加哪些限制条件?

题解

由于题目中的元素可以重复使用,那么这么道题就是一道完全背包问题

注意题目中顺序不同的会被视为不同的组合,那么其实就是求排列个数。

  1. 确定dp数组以及下标的含义

定义一个一维的动态规划数组 dp,其中 dp[i] 表示凑出总和为 i 的排列数。

  1. 确定递推公式
dp[i] += dp[i - nums[j]]

对于数组中的每个元素 num,遍历 dp 数组。

当 i > num 时,dp[i] += dp[i-num]。 其中,dp[i] 表示凑出总和为 i 的组合数,num 表示数组中的元素值。当选择当前元素 num 时,可能的组合数为 dp[i-num],因为只需要再凑出 i-num 的总和即可。因此,dp[i] 要加上 dp[i-num] 的值。遍历结束后,dp[target] 即为总和为 target 的元素组合个数。

  1. 初始化ap数组

因为递推公式 dp[i] += dp[i - nums[j]]的 缘故,dp[0] 要初始化为1,这样递归其他 dp[i] 的时候才会有数值基础。

所以讲 dp[0] 初始化为 1,其他位置初始化为 0

  1. 确定遍历顺序:

遍历 dp 数组时,外层循环按照 nums 中元素的顺序遍历,内层循环按照 dp 数组的范围遍历。

  1. 举例推导dp数组
i01234
dp11247

代码:

function combinationSum4(nums: number[], target: number): number {
  const dp = new Array(target + 1).fill(0);
  dp[0] = 1; 
  for (let i = 1; i <= target; i++) { 
    for (let num of nums) { 
      if (num <= i) { 
        dp[i] += dp[i - num];
      }
    }
  }
  return dp[target]; 
};

image.png