题解 | #换钱的最少货币数#

换钱的最少货币数

https://www.nowcoder.com/practice/4e05294fc5aa4d4fa8eacef2e606e5a8

方法一

参考动态规划的意义是什么? - 阮行止的回答1. 从一个生活问题谈起的思路。

#include<iostream>
#include<vector>

using namespace std;

int getMinCoin(vector<int>& arr, int aim){
    if(arr.empty() || aim<0){
        return -1;
    }
    else if(aim==0)
        return 0;
    int n=arr.size();
    //记录凑出0~aim元时,需要的最少货币数。
    //INT16_MAX表示凑不出来
    vector<int> dp(aim+1,INT16_MAX);
    dp[0]=0;//凑出0元,货币数是0
    for(int i=1;i<=aim;i++){
        for(int j=0;j<n;j++){
            //i-arr[j]>=0.表示当前货币i可以使用arr[j]换
            if((i-arr[j])>=0) {
                //dp[i-arr[j]]表示换了后的剩余货币数
                //想象成dp[i-arr[j]]已是最优解,
                //则换i元所需的货币数为i-arr[j]所需货币数+1
                dp[i] = min(dp[i],dp[i-arr[j]]+1);
            }               
        }
    }
    //说明给定的货币都换不出来
    if(dp[aim]==INT16_MAX)
        return -1;
    return dp[aim];    
}

int main()
{
    int n,aim;
    cin>>n>>aim;
    vector<int> arr(n);
    for(auto i=0;i<n;i++){
        cin>>arr[i];
    }

    auto res=getMinCoin(arr,aim);
    cout<<res<<endl;
    return 0;
}

方法二

根据左程云书中原问题的经典动态规划方法

#include<iostream>
#include<vector>

using namespace std;

//使用二维dp矩阵的解法
int getMinCoin(vector<int>& arr, int aim) {
    if (arr.empty() || aim < 0) {
        return -1;
    } else if (aim == 0)
        return 0;
    int n = arr.size(); //货币的种类数

    vector<vector<int>> dp(n,vector<int>(aim+1));
    //只使用dp[0]货币时,记录凑出0~aim元时,
    //需要的最少货币数,存入dp[0][j]。
    //INT16_MAX表示凑不出
    int maxV=INT16_MAX;
    for(int j=1;j<(aim+1);j++){
        dp[0][j]=maxV;
        //j-arr[0]>=0,表示当前价值j可以使用arr[0]凑
        //dp[0][j-arr[0]]!=INT16_MAX,表示使用arr[0]能凑出j-arr[0]
        if((j-arr[0])>=0 && dp[0][j-arr[0]]!=maxV){
            //只需在dp[0][j-arr[0]]使用的货币数上加1
            dp[0][j]=dp[0][j-arr[0]]+1;
        }
    }

    int cost=0;
    for (int i = 1; i < n; i++) {
        //由于dp[i][0]表示aim=0时需要的货币数,因此全为0。
        //所以j从1开始

        for (int j = 1; j < (aim+1); j++) {
            cost=maxV;
            if((j-arr[i])>=0 && dp[i][j-arr[i]]!=maxV){
                //cost表示使用了一个arr[i]货币,换出j价值所需的货币数
                cost=dp[i][j-arr[i]]+1;
            }
            //dp[i-1][j]表示不使用arr[i]货币时,换出j价值所需的货币数
            //当不用arr[i]货币就能换出j价值货币时,
            //所需的货币数小于使用了的,则不用arr[i]货币
            dp[i][j]=min(dp[i-1][j],cost);
        }
    }
    //说明给定的货币都换不出来
    if (dp[n-1][aim] == maxV)
        return -1;
    return dp[n-1][aim];
}

int main() {
    int n, aim;
    cin >> n >> aim;
    vector<int> arr(n);
    for (auto i = 0; i < n; i++) {
        cin >> arr[i];
    }

    auto res = getMinCoin(arr, aim);
    cout << res << endl;
    return 0;
}

方法三

根据左程云书中原问题在动态规划基础上的空间压缩方法

#include<iostream>
#include<vector>

using namespace std;

//使用一维dp矩阵的解法
int getMinCoin(vector<int>& arr, int aim) {
    if (arr.empty() || aim < 0) {
        return -1;
    } else if (aim == 0)
        return 0;
    int n = arr.size(); //货币的种类数

    //对dp进行滚动更新,起始时dp[j]代表只使用arr[0]货币时,
    //记录凑出j元时,需要的最少货币数。
    //终止时,dp[j]代表使用了arr[0~n-1]货币凑出j元时,需要的最少货币数。
    vector<int> dp(aim+1);
    //INT16_MAX表示凑不出
    int maxV=INT16_MAX;
    for(int j=1;j<(aim+1);j++){
        dp[j]=maxV;
        //j-arr[0]>=0,表示当前价值j可以使用arr[0]凑
        //dp[j-arr[0]]!=INT16_MAX,表示使用arr[0]能凑出j-arr[0]
        if((j-arr[0])>=0 && dp[j-arr[0]]!=maxV){
            //只需在dp[j-arr[0]]使用的货币数上加1
            dp[j]=dp[j-arr[0]]+1;
        }
    }

    int cost=0;
    for (int i = 1; i < n; i++) {
        //由于dp[0]表示aim=0时需要的货币数,因此全为0。
        //所以j从1开始       
        for (int j = 1; j < (aim+1); j++) {
            cost=maxV;
            if((j-arr[i])>=0 && dp[j-arr[i]]!=maxV){
                //cost表示使用了一个arr[i]货币,换出j价值所需的货币数
                cost=dp[j-arr[i]]+1;
            }
            //右侧的dp[j]未更新,表示不使用arr[i]货币时,换出j价值所需的货币数
            //当不用arr[i]货币就能换出j价值货币时,
            //所需的货币数小于使用了的,则不用arr[i]货币
            dp[j]=min(dp[j],cost);
        }
    }
    //说明给定的货币都换不出来
    if (dp[aim] == maxV)
        return -1;
    return dp[aim];
}

int main() {
    int n, aim;
    cin >> n >> aim;
    vector<int> arr(n);
    for (auto i = 0; i < n; i++) {
        cin >> arr[i];
    }

    auto res = getMinCoin(arr, aim);
    cout << res << endl;
    return 0;
}
全部评论

相关推荐

10-09 00:50
已编辑
长江大学 算法工程师
不期而遇的夏天:1.同学你面试评价不错,概率很大,请耐心等待;2.你的排名比较靠前,不要担心,耐心等待;3.问题不大,正在审批,不要着急签其他公司,等等我们!4.预计9月中下旬,安心过节;5.下周会有结果,请耐心等待下;6.可能国庆节前后,一有结果我马上通知你;7.预计10月中旬,再坚持一下;8.正在走流程,就这两天了;9.同学,结果我也不知道,你如果查到了也告诉我一声;10.同学你出线不明朗,建议签其他公司保底!11.同学你找了哪些公司,我也在找工作。
点赞 评论 收藏
分享
10-28 11:04
已编辑
美团_后端实习生(实习员工)
一个2人:我说几个点吧,你的实习经历写的让人觉得毫无含金量,你没有挖掘你需求里的 亮点, 让人觉得你不仅打杂还摆烂。然后你的简历太长了🤣你这个实习经历看完,估计没几个人愿意接着看下去, sdk, 索引这种东西单拎出来说太顶真了兄弟,好好优化下简历吧
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务