[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的一维数组滚动求取,节省了空间开销

posted @ 2017-09-04 13:53  木白的菜园  阅读(451)  评论(0编辑  收藏  举报