动态规划解题(leetcode322零钱兑换)

动态规划问题的一般形式就是求最值。最显著的特点是最优子结构和重叠子问题。最优子结构就是子问题的最优解,可以从子问题的最优结果推出更大规模问题的最优结果,可以用状态转移方程描述问题。重叠子问题可以通过创建备忘录dp[]避免重复计算。
零钱兑换的解题步骤:
1)先确定状态,也就是原问题和子问题中变化的变量,由于硬币数量可以无限,所以唯一确定的状态就是目标金额amount。
2)然后确定dp函数的定义,当前的目标金额是n,至少需要dp(n)个硬币凑出该金额。
3)确定选择并择优,无论当前的目标金额是多少,选择就是从面额列表coins中选则一个硬币,然后目标金额就会减少。
4)最后明确递归的终止条件,显然目标金额为0时,所需硬币数量为0,而当目标金额小于0时,无解。在动态规划中体现为子问题无解,跳过该次内层循环。
凑零钱问题的状态转移方程如下:

\[dp(n)=\begin{cases} 0 & n=0 \\ -1 & n<0 \\ min\{dp[n-coin]+1 | coin\in coins\} & n>0 \end{cases}\]

int coinChange(vector<int>& coins, int amount) {
        vector<int> dp(amount+1, amount+1);
        dp[0] = 0;
        for(int i = 0; i < dp.size(); i++)
        {
            for(int coin : coins)
            {
                if(i-coin < 0)
                    continue;
                dp[i] = min(dp[i], 1+dp[i-coin]);//索引为i-coin的dp[i-coin]加上for循环在这次选出的这个coin(即加1)

            }
        }
        return dp[amount] == amount+1 ? -1 : dp[amount];//为什么要这样返回??当给的coins不能凑出amount时就会出错,比如coins=[2],amount=3,amount无法凑出,此时应返回-1
    }
posted @ 2020-07-05 22:02  江中之苇  阅读(333)  评论(0编辑  收藏  举报