分治法:
原問題分解爲多個互不相交的子問題,組合子問題的解得到原問題的解。
動態規劃法:
不同的子問題具有公共的子子問題,使用分治法來解決具有公共子子問題的原問題,會有同一規模問題被多次重複計算。動態規劃法,將每一個規模的解存儲在表格中,使得不會重複計算。
求解最優化問題,問題有多個可行解,每個解對應一個值,找到最優解使得其對應的值最大或最小。
設計一個動態規劃算法:
1、刻畫一個最優解的結構特徵:原問題的最優解由相關的子問題最優解組合而成,根據題目信息,確定如何劃分原問題得到子問題?通常,劃分是由題目條件和要求來確定的。
2、遞歸定義最優解的值
3、採用自底向上的方法求出最優解的值(較帶有備忘錄的自頂向下方法代碼更爲簡單,判斷條件更少)
4、利用計算出的信息構造最優解
給定不同面額的硬幣 coins 和一個總金額 amount。編寫一個函數來計算可以湊成總金額所需的最少的硬幣個數。如果沒有任何一種硬幣組合能組成總金額,返回 -1。
示例 1:
輸入: coins = [1, 2, 5], amount = 11
輸出: 3
解釋: 11 = 5 + 5 + 1
解法一:自底向上,使用vector存儲各個規模下最優解對應的值
class Solution {
public:
int coinChange(vector<int>& coins, int amount)
{
vector<int> eles(amount+1);
for(int i=1;i<amount+1;i++)
{
int temp=0;
int min=INT_MAX;
for(int v:coins)
{
if(i-v>=0 && eles[i-v]>-1)
{
temp=eles[i-v]+1;
min=temp<min?temp:min;
}
}
eles[i]=min<INT_MAX?min:-1;//INT_MAX 代表沒有滿足此問題的解
}
return eles[amount];
}
};
解法二:自頂向下
/*class Solution {
public:
vector<int> memory;
int coinChange(vector<int>& coins, int amount)
{
if(amount<1)
return 0;
memory.resize(amount);
return coinChanges(coins,amount);
}
int coinChanges(vector<int>& coins, int amount) {
int count;
int min=INT_MAX;
if(amount<0) //存在一些選擇
return -1;
if (amount==0)
{
return 0;
}
if(memory[amount-1]!=0)
{
return memory[amount-1];
}
for(int coin:coins)
{
count=coinChanges(coins,amount-coin);
if (count>=0 && count+1<min)
{
min=count+1;
}
}
memory[amount-1]=min==INT_MAX?-1:min;//如果沒有合適的組合,返回-1
return memory[amount-1];
}
};*/