力扣322. 零钱兑换(动态规划:最值型问题)

力扣322. 零钱兑换(动态规划:最值型问题)

https://leetcode-cn.com/problems/coin-change/

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。

你可以认为每种硬币的数量是无限的。

示例 1:

输入:coins = [1, 2, 5], amount = 11
输出:3 
解释:11 = 5 + 5 + 1
示例 2:

输入:coins = [2], amount = 3
输出:-1
示例 3:

输入:coins = [1], amount = 0
输出:0
示例 4:

输入:coins = [1], amount = 1
输出:1
示例 5:

输入:coins = [1], amount = 2
输出:2

动态规划

最值型问题

自下而上

复杂度分析

  • 时间复杂度:O(Sn),其中 S 是金额,n 是面额数。我们一共需要计算 O(S) 个状态,S 为题目所给的总金额。对于每个状态,每次需要枚举 n 个面额来转移状态,所以一共需要 O(Sn) 的时间复杂度。

  • 空间复杂度:DP 数组需要开长度为总金额 S 的空间。

1、确定状态

最后一步:

子问题

与递归的区别:递归存在很多重复计算,

动态规划就是用空间换时间,将计算结果保留下来,并改变计算顺序

2、转移方程

3、初始条件和边界情况

4、计算顺序

//
//  main.cpp
//  dynamicprogramming
//
//  Created by MXQ on 2020/10/15.
//

#include <iostream>
#include<vector>
#include <algorithm>
#define INT_MAX 0x7fffffff
#define INT_MIN 0x80000000
using namespace std;

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        vector<int>f;
        int result=0;
        unsigned int n=coins.size();//number ofkinds of coins
        //initialization
        f.push_back(0);
        //从1计算到amount,计算顺序从小到大
        for (int i=1; i<=amount; i++) {
            //初始化为正无穷,拼不出
            f.push_back(INT_MAX);
            //看有多少个硬币种类
            for (int j=0; j<n; j++) {
                //i-coins[j]不能是负数,f[i-coins[j]]==INT_MAX的话没有必要算,代表的情况是拼不出
                if (i>=coins[j] && f[i-coins[j]]!=INT_MAX) {
                    if ((f[i-coins[j]]+1)<=(f[i])) {
                        f[i]=f[i-coins[j]]+1;
                    }
                }
            }
        }
        //题目说拼不出的话返回-1
        if (f[amount]==INT_MAX) {
            f[amount]=-1;
        }
        return f[amount];
    }
};
int main(int argc, const char * argv[]) {
    // insert code here...
    Solution s;
    vector<int> coins;
    coins.push_back(1);
    coins.push_back(2);
    coins.push_back(5);
    int amount=11;
    auto result=s.coinChange(coins,amount);
    std::cout << "how much: "<<result<<endl;
    std::cout << "Hello, World!\n";
    return 0;
}

动态规划解决的三类问题:

  1. 计数问题:多少种方式,多少种方法,how much

  2. 最大值最小值问题:max,min,最大最长

  3. 求存在性:取石子是否必胜,能不能选出k个数使和sum最大

C++最大值和最小值表示

#define INT_MAX 0x7fffffff
#define INT_MIN 0x80000000

猜你喜欢

转载自blog.csdn.net/qq_35683407/article/details/109091806