分治法:
原问题分解为多个互不相交的子问题,组合子问题的解得到原问题的解。
动态规划法:
不同的子问题具有公共的子子问题,使用分治法来解决具有公共子子问题的原问题,会有同一规模问题被多次重复计算。动态规划法,将每一个规模的解存储在表格中,使得不会重复计算。
求解最优化问题,问题有多个可行解,每个解对应一个值,找到最优解使得其对应的值最大或最小。
设计一个动态规划算法:
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];
}
};*/