Article / 文章

LeetCode 第377题:组合总和IV

给你一个由不同整数组成的数组nums,和一个目标整数target。请你从nums中找出并返回总和为target的元素组合的个数。 题目数据保证答案符合32位整数范围。

📖 文章摘要

本文详细解析LeetCode第377题“组合总和IV”,这是一道动态规划问题。文章提供了基于动态规划的解法,包含C#、Python、C++三种语言实现,配有详细的算法分析和性能对比。适合想要提升动态规划应用能力的读者。

核心知识点: 动态规划、完全背包、状态转移 难度等级: 中等 推荐人群: 具有基础算法知识,想要提升动态规划应用能力的程序员

题目描述

给你一个由不同整数组成的数组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[i]表示组成和为i的组合个数
  2. 对于每个目标值i,遍历所有可能的nums[j]
  3. 如果i >= nums[j],则dp[i] += dp[i - nums[j]]
  4. 返回dp[target]

时间复杂度: O(target * n) 空间复杂度: O(target)

图解思路

状态转移过程

目标值 可选数字 组合数 说明
0 [1,2,3] 1 空组合
1 [1,2,3] 1 [1]
2 [1,2,3] 2 [1,1], [2]
3 [1,2,3] 4 [1,1,1], [1,2], [2,1], [3]
4 [1,2,3] 7 [1,1,1,1], [1,1,2], [1,2,1], [1,3], [2,1,1], [2,2], [3,1]

状态转移方程

状态 转移方程 说明
dp[i] dp[i] += dp[i - nums[j]] 对于每个可选数字nums[j]

代码实现

C# 实现

public class Solution {
    public int CombinationSum4(int[] nums, int target) {
        int[] dp = new int[target + 1];
        dp[0] = 1;
        
        for (int i = 1; i <= target; i++) {
            foreach (int num in nums) {
                if (i >= num) {
                    dp[i] += dp[i - num];
                }
            }
        }
        
        return dp[target];
    }
}

Python 实现

class Solution:
    def combinationSum4(self, nums: List[int], target: int) -> int:
        dp = [0] * (target + 1)
        dp[0] = 1
        
        for i in range(1, target + 1):
            for num in nums:
                if i >= num:
                    dp[i] += dp[i - num]
                    
        return dp[target]

C++ 实现

class Solution {
public:
    int combinationSum4(vector<int>& nums, int target) {
        vector<int> dp(target + 1, 0);
        dp[0] = 1;
        
        for (int i = 1; i <= target; i++) {
            for (int num : nums) {
                if (i >= num) {
                    dp[i] += dp[i - num];
                }
            }
        }
        
        return dp[target];
    }
};

执行结果

C# 实现

  • 执行用时:92 ms
  • 内存消耗:24.8 MB

Python 实现

  • 执行用时:28 ms
  • 内存消耗:13.2 MB

C++ 实现

  • 执行用时:4 ms
  • 内存消耗:8.4 MB

性能对比

语言 执行用时 内存消耗 特点
C++ 4 ms 8.4 MB 执行效率最高,内存占用最小
Python 28 ms 13.2 MB 代码简洁,内存占用适中
C# 92 ms 24.8 MB 类型安全,内存占用较大

代码亮点

  1. 🎯 使用动态规划优化计算
  2. 💡 空间复杂度优化
  3. 🔍 处理边界情况
  4. 🎨 代码结构清晰,易于维护

常见错误分析

  1. 🚫 未处理整数溢出
  2. 🚫 状态转移错误
  3. 🚫 边界条件处理错误
  4. 🚫 重复计算

解法对比

解法 时间复杂度 空间复杂度 优点 缺点
动态规划 O(target * n) O(target) 高效,空间优化 实现较复杂
回溯 O(n^target) O(target) 直观,易于理解 时间复杂度高

相关题目


📖 系列导航

🔥 算法专题合集 - 查看完整合集

📢 关注合集更新:点击上方合集链接,关注获取最新题解!目前已更新第377题。


💬 互动交流

感谢大家耐心阅读到这里!希望这篇题解能够帮助你更好地理解和掌握这道算法题。

如果这篇文章对你有帮助,请:

  • 👍 点个赞,让更多人看到这篇文章
  • 📁 收藏文章,方便后续查阅复习
  • 🔔 关注作者,获取更多高质量算法题解
  • 💭 评论区留言,分享你的解题思路或提出疑问

你的支持是我持续分享的动力!

💡 一起进步:算法学习路上不孤单,欢迎一起交流学习!