LeetCode 第518題:零錢兌換 II

1、前言

題目描述

2、思路

本題使用完全背包的思路,那完全背包跟 0-1 背包有何區(qū)別呢?

0-1 限制了物品的數(shù)量,物品并不是無限的。假設(shè)有物品 weight 跟物品的價(jià)值 value,weight_i 表示每個(gè)物品的重量,value_i 表示每個(gè)物品對應(yīng)的價(jià)值,在不超過背包容量的情況下怎樣才能使得價(jià)值最大?其實(shí)對于每個(gè)物品來說,都可以放與不放。那么定義一個(gè)二位數(shù)組 dp[i][j] 表示在選擇物品 i 、背包容量為 j 的情況下價(jià)值最大。

那么對于 dp[i][j] 來說,存在放第 i 個(gè)物品跟不放第 i 個(gè)物品。

在不放第 i 個(gè)物品的情況下,直接繼承上一個(gè)背包的數(shù)據(jù)情況,即 dp[i][j] = dp[i - 1][j]。

在放第 i 個(gè)物品的情況下,那么需要加上第 i 個(gè)物品的價(jià)值 value_i[i - 1](數(shù)組從 0開始),然后需要加上去掉 i 的重量的情況下,應(yīng)該由哪個(gè)數(shù)據(jù)推導(dǎo)過來,即 dp[i - 1][j - weight_i[i - 1]],所以 dp[i][j] = dp[i - 1][j - weight_i[i - 1]] + value_i[i - 1]。

所以最大價(jià)值為 dp[i][j] = max {dp[i - 1][j], dp[i - 1][j - weight_i[i - 1]] + value_i[i - 1]}

要牢牢記住一點(diǎn),動(dòng)態(tài)規(guī)劃是自底向上,由已知推到未知。

那么對應(yīng)完全背包來說,物品的數(shù)量是無限的,那么也存在上面放與不放的情況。
針對這題,針對物品 i,存在放0個(gè),放1個(gè),放 k 個(gè),所以 dp[i][j] = dp[i - 1][j - 0 * coins[i]] + dp[i - 1][j - 1 * coins[i]] ....,而 dp[i][j - coins[i]] = dp[i][j - coins[i] - 0 * coins[i]] + dp[i][j - coins[i] - 1 * coins[i]] + ...。

那么,上面兩式相減得:dp[i][j]?dp[i][j?coins[i]]=dp[i?1][j],即 dp[i][j] = dp[i - 1][j] + dp[i][j - coins[i]]

3、代碼

初始代碼:

public class Solution {

    public int change(int amount, int[] coins) {
        int len = coins.length;
        if (len == 0) {
            if (amount == 0) {
                return 1;
            }
            return 0;
        }

        int[][] dp = new int[len][amount + 1];
        // 題解中有說明應(yīng)該如何理解這個(gè)初始化
        dp[0][0] = 1;

        // 填第 1 行
        for (int i = coins[0]; i <= amount; i += coins[0]) {
            dp[0][i] = 1;
        }

        for (int i = 1; i < len; i++) {
            for (int j = 0; j <= amount; j++) {
                for (int k = 0; j - k * coins[i] >= 0; k++) {
                    dp[i][j] += dp[i - 1][j - k * coins[i]];
                }
            }
        }
        return dp[len - 1][amount];
    }
}

優(yōu)化后代碼:


class Solution {
    public int change(int amount, int[] coins) {
        int[][] dp = new int[coins.length + 1][amount + 1];
        for (int i = 0; i < dp.length; i++) {
            // 沒有 amount 時(shí),不用湊數(shù),直接得1
            // dp[0][i] 為 0,但是數(shù)組默認(rèn)都是0,所以不用寫
            dp[i][0] = 1;
        }

        for(int i = 1; i <= coins.length; i++){
            for(int j = 1; j <= amount; j++){
                if(j - coins[i - 1] < 0){
                    dp[i][j] = dp[i - 1][j];
                }else {
                    dp[i][j] = dp[i - 1][j] + dp[i][j - coins[i - 1]];
                }
            }
        }

        return dp[coins.length][amount];
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容