leetcode 322. 零钱兑换 思考分析
目录
- 1、题目
- 2、思路分析
- 3、参考链接
1、题目
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
你可以认为每种硬币的数量是无限的。
提示:
1 <= coins.length <= 12
1 <= coins[i] <= 231 - 1
0 <= amount <= 104
2、思路分析
这一题和leetcode 39. 组合总和 思考分析有点像,不过要求不同。
39题要求的是所有解的集合,而这一题求的是最优解。
所以直接套用39回溯思路,然后从子解中找到最小的即可,貌似也是能做的,不过会超时。。。
其实这一题是一道动态规划题:
如果想求amount = 11时的最少硬币数(原问题),如果知道amout =10的最少硬币数(子问题),你只需要把子问题的答案加一(再选一枚1元的硬币),因为硬币的数量是没有限制的,当然也可能是amout =6的最少硬币数加上一个面额为5的硬币。这时候就需要取最少的硬币数了。
子问题之间是相互独立的。
1、分析最优子结构:
凑成面值为 11 的最少硬币个数可以由以下三者的最小值得到:
凑成面值为 10 的最少硬币个数 + 面值为 1 的这一枚硬币;
凑成面值为 9 的最少硬币个数 + 面值为 2 的这一枚硬币;
凑成面值为 6 的最少硬币个数 + 面值为 5 的这一枚硬币。
dp[11] = min (dp[10] + 1, dp[9] + 1, dp[6] + 1)
2、确定【DP状态】
dp[i] :凑齐总价值 i 需要的最少硬币个数;
3、确定状态转移方程
需要注意的地方:
单枚硬币的面值首先要小于等于 当前要凑出来的面值。
时间复杂度:O(N \times amount)O(N×amount),这里 NN 是可选硬币的种类数,amountamount 是题目输入的面值;
空间复杂度:O(amount)O(amount),状态数组的大小为 amountamount。
由于dp数组是自底向上求解的,所以过程中不会出现重叠子问题
需要注意的地方:
1、数组初始化把初值amount+1换成Integer.MAX_VALUE为什么就不行了 ?
如果初值赋值为正无穷,dp[i - coin] +1 可能会发生整型溢出。
2、循环的判断条件if (i - coin >= 0 && dp[i - coin] != amount + 1)为什么要判断 dp[i - coin] != amount + 1呢
amount + 1 在这里表示的是当前状态表示的金额不能被候选硬币的和表示。
去掉dp[i-coin] != amount + 1 这个判断条件也是可以的, 因为若是 dp[i-coin] = amount + 1, 在下一步 dp[i] = Math.min(dp[i], 1 + dp[i - coin]) 也会将amount+1+1这个值过滤掉的,即amount + 1仍然是无效的。 因为数组中的有效值不会超过amount+1,就算有1块钱的硬币,最大值也就是amount,因此在取两个数的最小值时已经自动将amount+1这个值过滤掉了。
3、参考链接
动态规划、完全背包、BFS(包含完全背包问题公式推导)
labuladong的公众号文章
总结
以上是生活随笔为你收集整理的leetcode 322. 零钱兑换 思考分析的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 【C++grammar】文件系统以及pa
- 下一篇: 二分法:两个有序数组长度为N,找到第N、