背包问题中“遍历方向”与“内外循环”对结果的影响总结
核心关系表
| 问题类型 | 内外循环顺序 | 背包容量遍历方向 | 结果特征(核心影响) | 典型题目 | 特殊案例验证(错误vs正确) | 
|---|---|---|---|---|---|
| 01背包(物品不可重复) | 物品外循环 | 逆序(从大到小) | 每个物品仅用1次,不考虑选择顺序 | 分割等和子集、目标和 | 若正序遍历,会重复选物品(如nums=[2], target=4会误判为可分割) | 
| 完全背包-组合 | 物品外循环 | 正序(从小到大) | 物品可重复用,不考虑顺序(组合唯一) | 零钱兑换II(凑数方法数) | 若背包外循环,会多算排列(如coins=[1,2], amount=3会从2种→3种) | 
| 完全背包-排列 | 背包外循环 | 正序(从小到大) | 物品可重复用,考虑顺序(排列不同) | 组合总和IV(凑数方法数) | 若物品外循环,会少算排列(如nums=[1,2], target=3会从4种→2种) | 
| 完全背包-最值 | 内外循环均可 | 正序(从小到大) | 物品可重复用,与顺序无关(最值唯一) | 零钱兑换(最少硬币数) | 无论内外循环,结果一致(如coins=[1,2,5], amount=11均返回3) | 
结合特殊案例详解
一、01背包(物品不可重复使用)
核心逻辑:每个物品只能选1次,需通过“物品外循环+背包逆序遍历”避免重复使用。
特殊案例:nums=[2,3,5],判断能否分割出和为5的子集(正确答案:能,选5或2+3)
- 
错误做法(正序遍历背包): 
 处理num=2时,正序遍历j=2→5,会更新dp[2]=True,进而在j=4时用dp[2]更新dp[4]=True(相当于选了两次2),最终错误判断“能分割出和为4的子集”(实际nums中只有1个2)。
- 
正确做法(逆序遍历背包): def canPartition(nums): target = 5 dp = [False] * (target + 1) dp[0] = True for num in nums: # 逆序遍历:从大到小,避免同一物品被重复选 for j in range(target, num - 1, -1): dp[j] = dp[j] or dp[j - num] return dp[5] # 返回True(正确)逆序遍历确保每个物品仅被使用1次,如处理num=2时,j=2更新dp[2],但j=4不会再用dp[2]的新值(因j=4在j=2之前遍历),避免重复选择。 
二、完全背包-组合(物品可重复,不考虑顺序)
核心逻辑:物品可重复使用,通过“物品外循环+背包正序遍历”实现重复使用,且保证组合顺序不影响结果。
特殊案例:coins=[1,2],amount=3(正确组合数:2种:1+1+1、1+2)
- 
错误做法(背包外循环): 
 先遍历金额j=1→3,再遍历硬币,会将“1+2”和“2+1”视为两种组合,最终结果为3(错误)。
- 
正确做法(物品外循环): def change(amount, coins): dp = [0] * (amount + 1) dp[0] = 1 for coin in coins: # 先固定硬币,保证顺序唯一 for j in range(coin, amount + 1): dp[j] += dp[j - coin] return dp[3] # 返回2(正确)物品外循环确保“先1后2”的固定顺序,不会出现“先2后1”的重复计数,组合数正确。 
三、完全背包-排列(物品可重复,考虑顺序)
核心逻辑:物品可重复使用,通过“背包外循环+背包正序遍历”实现重复使用,且保证顺序不同视为不同结果。
特殊案例:nums=[1,2],target=3(正确排列数:4种:1+1+1、1+2、2+1)
- 
错误做法(物品外循环): 
 先遍历物品1再遍历物品2,会将“1+2”和“2+1”视为同一种,最终结果为2(错误)。
- 
正确做法(背包外循环): def combinationSum4(nums, target): dp = [0] * (target + 1) dp[0] = 1 for j in range(1, target + 1): # 先固定金额,再试所有物品 for num in nums: if j >= num: dp[j] += dp[j - num] return dp[3] # 返回4(正确)背包外循环允许每个金额下尝试所有物品,自然包含“1+2”和“2+1”两种顺序,排列数正确。 
四、完全背包-最值(特殊情况:顺序不影响结果)
核心逻辑:求“最少/最多”等最值时,因顺序不影响结果,内外循环可互换,只需保证正序遍历金额。
特殊案例:coins=[1,2,5],amount=11(正确答案:3)
- 
物品外循环: for coin in coins: for j in range(coin, amount + 1): dp[j] = min(dp[j], dp[j - coin] + 1) # 结果3(正确)
- 
金额外循环: for j in range(1, amount + 1): for coin in coins: if j >= coin: dp[j] = min(dp[j], dp[j - coin] + 1) # 结果仍为3(正确)
原因:最值问题只关心“是否存在更少/更多的数量”,而不关心“用了哪些顺序”,因此循环顺序不影响结果。
总结:核心判断依据
- 
是否允许重复使用物品: - 逆序遍历背包 → 01背包(如分割等和子集,避免重复选2);
- 正序遍历背包 → 完全背包(如零钱兑换,允许重复用2元)。
 
- 
是否考虑顺序(仅影响“计数类”问题): - 物品外循环 → 组合(如零钱兑换II,1+2和2+1算1种);
- 背包外循环 → 排列(如组合总和IV,1+2和2+1算2种);
- 最值类问题(如最少硬币数) → 顺序无关,循环可互换。
 
跟我一起念:
物品只能用1次的,逆序遍历;跟顺序有关的,背包在外循环!
物品只能用1次的,逆序遍历;跟顺序有关的,背包在外循环!
物品只能用1次的,逆序遍历;跟顺序有关的,背包在外循环!
 
                    
                 
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号