如何将一个可以用背包问题解决的问题,转换为背包问题。根据上一篇的文章,已经能Get到背包问题,是一个组合问题,将一组数据分组,去装满一个容量为target的背包。分割等和子集就是这样一种情况。判断dp[target] = target。如果有就说明找到了。
- 最后一块石头的重量
一开始看到没有想到能够转换为将一组石头尽可能分成重量一样的两组。如果能想到这一步,思路就比较清楚了。背包重量是sum / 2。目的是尽可能的多装石头。
- 目标和
这一回的问题和之前相比不同的地方在于,目的是要求出方法。这个问题的难点还在于如何寻找一个“背包”,一个确定的目的使得能够进行求解。因为是添加+,-,符号,最后问题会变成left - right = target的判断。又因为left + right = sum。所以,问题能够转化为找到能够累加成left的可能种数。
- 一和零
值得表扬的是在自己分析的时候,能够意识到可以通过两个维度解决这个问题。但是没有实现。思路是遍历字符串,同时统计0,1的个数。然后遍历背包容量dp[i][j] = max(dp[i - zeroNum][j - oneNum] + 1, dp[i][j])
- 零钱兑换II
和之前题目不同的地方在于,不同面额的硬币可以用无限个,因此要改变遍历顺序。完全背包要注意两个遍历顺序,首先是双重遍历的先后关系,即先遍历背包,还是先遍历物品。其次是在遍历背包的时候,从前向后遍历还是从后向前遍历。第一个问题,由于是组合问题,因此先遍历物品,确保在计算方法个数的时候不会再考虑之前的元素。所以,假如是排列问题,就应该把物品放在后面遍历。 第二个问题。背包容量应该从前向后遍历,满足物品可以无限次方的设定。
- 组合总和IV
给定一个由正整数组成且不存在重复数字的数组,找出和为给定目标正整数的组合的个数。 顺序不同视为不同的组合。因为只要求个数,因此,用动态规划来做。如果要把每个组合输出出来,那就要用回溯法。这里和前面的不同在于需要将遍历物品放在第二层循环。
- 零钱兑换
组合成amount 的最小硬币个数,dp[j] = min(dp[j - coins[i]] + 1, dp[j]) 这里出现了min,所以要注意初始化的操作。dp[0] = 0,其余的为INT_MIN
还是挺难的,不过二刷的时候比第一遍做的感觉要好很多,经过自己的总结,更能针对题目的要求对代码进行改进。