zoukankan      html  css  js  c++  java
  • [DP]换钱的最小货币数

    题目一

    给定数组arr,数组中有N个元素,其中所有的之都为整数且不重复.每个只代表一种面值的货币,每种面值的货币可以使用任意张,在给定一个整数aim代表要找的钱数,求组成aim的最少货币数.

    解法

    依然是用二维数组分析的动态规划问题,数组dp长为N行aim-1列.其中dp[i][j]代表用arr[0...i]中出现的面值构成钱数为j所需要的钱的最小张数.那么就有
    dp[i][j] = min{dp[i-1][j], dp[i][j - arr[i]] + 1}
    整个过程中时间复杂度和空间复杂度分别为O(N*aim)

    代码

    int minCoins1(int arr[], int length, int aim) {
        if (length == 0 || aim == 0)
            return 0;
        if (aim < 0)
            return -1;
    
        int maxInt = INT_MAX;
        int dp[length][aim + 1];
        for (int j = 1; j < aim + 1; j ++) { //初始化第一行
            if (j - arr[0] >=0 && j % arr[0] == 0)
                dp[0][j] = j / arr[0];
            else
                dp[0][j] = maxInt;
        }
    
        //从左到右,从上倒下计算dp矩阵
        for (int i = 1; i < length; i ++) {
            for (int j = 1; j <= aim; j ++) {
                if (j - arr[i] >= 0 && dp[i][j - arr[i]] != maxInt)
                    dp[i][j] = min(dp[i - 1][j], dp[i][j - arr[i]] + 1);
                else
                    dp[i][j] = dp[i - 1][j];
            }
        }
    
    //    for (int i = 0; i < length; i ++) {
    //        for (int j = 0; j < aim + 1; j ++)
    //            cout<<dp[i][j]<<" ";
    //        cout<<endl;
    //    }
    
        return dp[length - 1][aim] != maxInt ? dp[length - 1][aim]:-1;
    }
    

    输入

    arr={5,2,3} 20
    arr={3,5} -1

    输出

    4
    -1

    题目二

    给定数组arr,arr中所有的值都为整数.每个值仅代表一张钱的面值,在给定一个整数aim代表要找的钱数, 求组成aim的最少货币数.

    解法

    同上面一样,我们需要的dp矩阵为N行aim+1列.dp[i][j]代表用arr[0...i]中的钱组成钱数为j所用的最小张数张数.和题目一不同的是根据题意,这里是不允许重复使用面值的.所以dp矩阵初始化第一行是不同的.但是他们有相同的转移方程:
    dp[i][j] = min{dp[i-1][j], dp[i][j - arr[i]] + 1}
    复杂度也和题目一相似

    代码

    int minCoins2(int arr[], int length, int aim) {
        if (aim < 0)
            return -1;
        if (length == 0 || aim == 0)
            return 0;
    
        int maxInt = INT_MAX;
        int dp[length][aim + 1];
        for (int i = 0; i < aim + 1; i ++) { //初始化第一行
            if (i == arr[0])
                dp[0][i] = 1;
            else
                dp[0][i] = maxInt;
        }
    
        for (int i = 1; i < length; i++) {
            for (int j = 1; j <= aim; j++) {
                if (j - arr[i] >= 0 && dp[i - 1][j - arr[i]] != maxInt)
                    dp[i][j] = min(dp[i - 1][j - arr[i]] + 1, dp[i - 1][j]);
                else
                    dp[i][j] = dp[i - 1][j];
            }
        }
    
        return dp[length - 1][aim] != maxInt ? dp[length - 1][aim]:-1;
    }
    

    输入

    arr={5,2,3}, aim = 20
    arr = {5,2,5,3},aim = 15

    输出

    -1
    4

    拓展

    上面两题都是用的经典动态规划的方式,使用的二维数组.一个常用的优化方式是使用长度为N的一维数组滚动求取,节省了空间开销

  • 相关阅读:
    关于C语言字符串
    进程间通信方式总结
    数据结构(3)-----链表
    Oracle查看用户所在表空间
    oracle linux了解基本命令行
    关于分区技术的索引 index
    oracle闪回表详解
    转:深入学习Oracle分区表及分区索引
    第一章 基本的SQL语句 (SQL基础)
    linux根分区扩容
  • 原文地址:https://www.cnblogs.com/mooba/p/7473292.html
Copyright © 2011-2022 走看看