动态规划学习的第一天

本篇博客内容参考学习了https://labuladong.gitbook.io/algo/中的内容(建议大家可以去看这个,里面算法干货很多)。

动态规划问题的一般形式就是求最值,例如求最长递增子序列,最小编辑距离之类的。其核心问题就是穷举(我个人认为其实计算机处理大部分问题都是通过穷举来实现的,只不过加了一些优化的过程在其中)。

动态规划的三要素:重叠子问题、最优子结构、状态转移方程。

我们在利用递归解决一些问题的时候,会经常出现重复计算的问题,这些就可以被看成是重叠子问题。在递归中可以加个备忘录,将每个子问题的答案添加到这个备忘录中,然后每次计算的时候先去备忘录查询是否之前已经解决过这个问题。在动态规划中可以使用dp table去解决。这种带备忘录的递归方法与动态规划相比,最大的区别是前一种是自顶向下的,而后一种是自底向上的。

要符合最优子结构,问题之间必须是相互独立的,就是一个子问题的结果是不会影响到另外子问题的结果。另外最优子结构并不是动态规划专有的,它是很多问题都有的一种特定性质。它就是指从子问题的最优结果中推出更大规模问题的最优结果。

状态转移方程直接代表着暴力解法。

如何列出正确的状态转移方程:

1.确定【状态】,也就是原问题和子问题中变化的变量。

2.确定dp函数的定义。

3.确定选择并择优,也就是对于每个状态,可以做出什么选择改变当前状态。

 

dp数组的遍历方向:在动态规划中dp数组的遍历顺序有正向遍历、反向遍历,有的时候还会有斜向遍历。

主要需要注意的是这两个点:

1、遍历的过程中,所需的状态必须是已经计算出来的。

2、遍历的终点必须是存储结果的那个位置。

 

经典问题:凑零钱

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。

示例 1:

输入: coins = [1, 2, 5], amount = 11

输出: 3

解释: 11 = 5 + 5 + 1

示例 2:

输入: coins = [2], amount = 3

输出: -1

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/coin-change
动态规划的方法。(利用c语言实现)

//dp[i]=x表示当目标金额为i时,至少需要x枚硬币。

int coinChange(int* coins,int coinsSize,int amount){

  int *dp=(int*)malloc(sizeof(int)*(amount+1));

  for(int i=0;i<=amount;i++)

{

  for(int j=0;j<coinSize;j++)

{

  if(i-coins[j]<0) continue;

  dp[i]=fmin(dp[i],1+dp[i-coins[j]]);

}

}

int res=(dp[amount]==amount+1)?-1:dp[amount];

  free(dp);

  return res;

}

posted @ 2020-05-18 16:21  程序媛猿~  阅读(158)  评论(0)    收藏  举报