完全背包问题中「排列数」与「组合数」的核心区别

🎯 一句话理解

  • 求组合数(不计顺序) → 外层遍历物品,内层遍历背包容量

  • 求排列数(计顺序) → 外层遍历背包容量,内层遍历物品


🎲 举例说明

假设有硬币 [1, 2, 3],目标金额是 4,要求凑成的方法数:

1. 组合数(顺序无关):

比如:[1, 2, 1][2, 1, 1][1, 1, 2] 视为同一种方案,因为它们元素一样,只是顺序不同。

for i := 0; i < len(nums); i++ {       // 物品在外层
    for j := nums[i]; j <= target; j++ { // 容量在内层
        dp[j] += dp[j - nums[i]]
    }
}

这种写法只会把每组物品组合一次,不考虑排列方式。


2. 排列数(顺序有关):

比如:[1, 2, 1][2, 1, 1][1, 1, 2] 视为3种不同方案

for j := 0; j <= target; j++ {       // 容量在外层
    for i := 0; i < len(nums); i++ { // 物品在内层
        if j >= nums[i] {
            dp[j] += dp[j - nums[i]]
        }
    }
}

这样每次容量增加时,都会把所有可放的物品都考虑一遍 ⇒ 排列自然产生了。


✅ 总结对比

目标外层循环内层循环特点
组合数(无序)遍历物品 i遍历容量 j顺序不会重复
排列数(有序)遍历容量 j遍历物品 i会计算所有顺序

🧠 记忆口诀

🎯 组合外层物品,排列外层背包。

详细解释 组合外层物品,排列外层背包

🎯 问题背景

我们有硬币 coins = [1, 2, 3],目标是金额 4。我们想知道有多少种方案凑出金额 4:


🧮 什么是组合数(不计顺序)?

  • 组合数不区分顺序:[1,1,2][2,1,1][1,2,1] 是同一种组合。

  • 所以我们只想知道「有哪些组合方式」,不在意顺序。


✅ 为什么组合数要先遍历物品?

我们看以下代码:

dp := make([]int, target+1)
dp[0] = 1
for i := 0; i < len(coins); i++ {       // 外层:物品(硬币)
    for j := coins[i]; j <= target; j++ { // 内层:背包容量
        dp[j] += dp[j - coins[i]]
    }
}

🌱 核心思想:

每次选一个硬币coins[i],我们更新所有能放它的位置,但每个 dp[j] 只会累加来自当前物品之前的组合。

这样做的结果是:

  • 所有组合只计算一次,避免了顺序重复。


✍️ 举个例子

第一层循环:i = 0(coin = 1)

更新 dp[1], dp[2], dp[3], dp[4],只用 1 元硬币。

此时:

dp = [1 1 1 1 1]

表示只用 1 元可以组成的方法数,只有一种 [1,1,1,1]


第二层循环:i = 1(coin = 2)

我们再用 2 元更新,但只能在原有的基础上增加。

  • dp[2] += dp[0] → [2]

  • dp[3] += dp[1] → [1,2]

  • dp[4] += dp[2] → [2,2]

更新后:

dp = [1 1 2 2 3]

说明方法数是:[1,1,1,1], [1,1,2], [2,2], 不会重复 [2,1,1][1,2,1] 等顺序。


📦 如果调换循环顺序会怎样?

比如改为这样:

for j := 0; j <= target; j++ {
    for i := 0; i < len(coins); i++ {
        if j >= coins[i] {
            dp[j] += dp[j - coins[i]]
        }
    }
}

这时每个 j 都会尝试所有硬币,所以:

  • dp[3] 会通过 [1,2],也会通过 [2,1],两次都被算入。

  • 所以是排列数(考虑顺序)。


🔁 总结

目标外层循环结果特性会不会重复顺序
组合数物品在外不计顺序不会
排列数背包在外顺序不同都算

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值