LeetCode解題 零錢兌換

2021-10-11 11:04:14 字數 4462 閱讀 6549

動態規劃是 求解最優化問題的一種常用策略

零錢兌換   322. 零錢兌換

給定不同面額的硬幣 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

貪心只看眼前最優,但不一定得到全域性最優解。如:41 = 25 10 5 1 最優解 20 20 1

如果沒有如下限制

1. 如果面值從1開始,此時一定有解(最壞情況 零錢面值都是1)

則此時如下條件一定可以不滿足: 如果沒有任何一種硬幣組合能組成總金額,返回 -1。( 即如果amount數額湊不齊,返回 -1 ) 

2. coins 陣列逆序排序

如下解題思路為解決 陣列逆序排序問題,可忽略

陣列逆序排序,需要 int 是包裝型別 integer

1. collections.reverseorder()

// 可以用此方法進行逆序排序,但是int陣列必須是integer包裝類 型別

arrays.sort(coin, collections.reverseorder());

2. 傳入比較器

// 簡寫如下

arrays.sort(coins, (integer f1, integer f2) -> f2 - f1); // 傳入比較器,逆序排序

即arrays.sort(coins,(integer f1,integer f2)->);

當然可以先將其轉為包裝類

integer coin = new integer[coins.length];

for (int i = 0; i 如果沒有如下限制

1. 如果沒有任何一種硬幣組合能組成總金額,返回 -1。( 即如果amount數額湊不齊,返回 -1 ) 

參考 斐波那契

// 此處類別 fib 1. fib有2個選項 零錢兌換有4個選項 2.都有重複計算--記憶化搜尋 優化

static int fib(int n)

/**

* 暴力遞迴(自頂向下的呼叫,出現了重疊子問題)

** 貪心策略得到的並非最優解 只看眼前

** dp(20) 湊到20分需要的最少硬幣個數

** dp(41) 湊到41分需要的最少硬幣個數

** dp(n) 湊到n分需要的最少硬幣個數

** 第一次選擇了25分的硬幣,現在還差 n-25分

* dp[n-25]湊到n-25需要的最少硬幣個數

* 如果第一次選擇的了25分的硬幣,那麼 dp(n)=dp(n-25)+1 // +1,已經選擇了1枚硬幣,25分的硬幣

*/static int coinchange2_(int n)

/**

* 記憶化搜尋(自頂向下的呼叫)

* dp[1]=dp[5]=dp[20]=dp[25]=1 湊夠1、5、20、25分需要的最少硬幣個數都是 1 枚

*/static int coinchange2(int n) ;

for (int face : faces)

return coinchange2(n, dp);

}static int coinchange2(int n, int dp)

return dp[n]; // 已經算過,直接返回。記憶化搜尋

}// 此處類別 fib 1. fib有2個選項 零錢兌換有4個選項 2.都有重複計算--記憶化搜尋 優化

static int fib(int n)

[ 效能分析 ]

如果沒有如下條件限制

1. 如果沒有任何一種硬幣組合能組成總金額,返回 -1。( 即如果amount數額湊不齊,返回 -1 ) 

/*

dp[n] 湊夠n分需要的最少硬幣個數

dp[i]=min+1

解讀:dp[i] 湊夠i分需要的最少硬幣個數 = 湊夠 最小個數,再+1個硬幣

coins=

amount=5 dp=[0, 0, 0, 0, 0, 1]

amount=6 dp=[0, -2147483648, -2147483648, -2147483648, -2147483648, 1, -2147483647]

*/static int coinchange3_1(int coins,int amount)

dp[i]=min+1;

}system.out.println(arrays.tostring(dp));

return dp[amount];

}

//  dp[n] 湊夠n分需要的最少硬幣個數

/* // 如果amount數額湊不齊。即:如果沒有任何一種硬幣組合能組成總金額,返回 -1。

coins=

amount=5 dp=[0, -1, -1, -1, -1, 1]

amount=6 dp=[0, -1, -1, -1, -1, 1, -1]

amount=20 dp=[0, -1, -1, -1, -1, 1, -1, -1, -1, -1, 2, -1, -1, -1, -1, 3, -1, -1, -1, -1, 1]

*/static int coinchange3_2(int coins,int amount) 沒有1,此時dp[1]=-1 dp[1~4]=-1

continue;

int v = dp[i - coin];

// 如果面值不是從1開始,那麼湊夠dp[i]需要的最少硬幣個數v就是-1.即:如果,dp[1~4]=-1

// 如果湊夠dp[i]需要的最少硬幣個數v >=min ,那麼沒有必要更新min.即:如果,amount=20

// v=dp[20-20]=0 (湊夠0分需要0枚);或者那麼v=dp[20-15]=3 (湊夠15分需要3枚)

// 則 v=3 答案捨棄

if (v < 0 || v >= min) // v=-1 即沒法湊

continue;

min = v;

}if (min == integer.max_value) else

}system.out.println(arrays.tostring(dp));

return dp[amount];

}

//  看不懂如上沒關係,哈哈,讀者可直接看如下

/*

假如有coins= 需要 湊夠 20

1.第乙個continue 過濾 湊夠 1-4

2.第二個continue 過濾 湊夠 6-9 11-14 16-19

v >= min 繼續過濾 湊夠15 需要3,但是用20湊夠20需要0

*/// dp[n] 湊夠n分需要的最少硬幣個數

/* // 如果amount數額湊不齊。即:如果沒有任何一種硬幣組合能組成總金額,返回 -1。

coins=

amount=6 dp=[0, -1, -1, -1, -1, 1, -1]

amount=12 dp=[0, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1]

*/// _322_零錢兌換

static int coinchange(int coins,int amount) 沒有1,此時dp[1]=-1 dp[1~4]=-1

continue;

int v = dp[i - coin];

// v < 0 即沒辦法湊; 即 dp[6~9] dp[11~14] dp[16~19] ;

// v >= min已經有更優解; 即 先用20湊夠20需要0;用15湊夠20還需要5 需要3

if (v < 0 || v >= min)

continue;

min = v;

}if (min == integer.max_value) else

}system.out.println(arrays.tostring(dp));

return dp[amount];

}

[ 效能分析 ]

零錢兌換 leetcode

思路 建乙個動態陣列dp,大小為amount 1,dp裡面的值初始化為amount 1。dp i 表示總金額i最少可以用dp i 的零錢兌換,如果coins j 比i小,那麼總金額i可以由dp i conis j 再加上這枚零錢構成,dp i min dp i dp i coins j 1 如果dp...

leetcode零錢兌換

1.遞迴 回溯 記錄每種錢幣能夠使用的最大數量,然後遍歷每一種情況,求錢幣數量最小的,但會超時 2.動態規劃 設定dp amount 1 初始值設為0x3f3f3f3f,即為無窮大 dp i 表示總量是i是,coins中的金幣組成i所需的最小金幣個數 此處以錢幣為1 2 5,總額是11舉例 dp 1...

LeetCode 零錢兌換

q 給定不同面額的硬幣 coins 和乙個總金額 amount。編寫乙個函式來計算可以湊成總金額所需的最少的硬幣個數。如果沒有任何一種硬幣組合能組成總金額,返回 1。示例 1 輸入 coins 1,2,5 amount 11 輸出 3 解釋 11 5 5 1 示例 2 輸入 coins 2 amou...