动态规划五步骤:
- 认识dp数组的索引含义
- 寻找递推公式
- dp数组初始化
- 寻找遍历顺序
- 打印dp数组
打家劫舍

思路:
递归:
当我们计算如果有n家可以偷的房屋时,我们从最后一家开始看起,偷最后一家后的最大金额考虑是:
1.我们偷第n家,这时第n-1家不可以偷,所以最大金额是前n-2家最大的值加上第n家的金额。
2.我们不偷第n家,这时第n-1家可以偷,所以最大金额就是前n-1家能偷的最大值。
边界条件是:
1.一家都没有,返回0。
2.有一家能偷,返回此家能偷的钱。
3.有两家能偷,返回这两家最大的钱。
代码:
var rob = function(nums) {function cal(n){if(n==0)return 0;if(n==1)return nums[0];if(n==2)return Math.max(nums[0],nums[1]);if(n>2)return Math.max(cal(n-1),cal(n-2)+nums[n-1]);}return cal(nums.length);};
代码是我自己写的,很不幸的是它超时了。。。
这时我们来看官方给出的答案:
class Solution {public int rob(int[] nums) {if (nums == null || nums.length == 0) {return 0;}int length = nums.length;if (length == 1) {return nums[0];}int[] dp = new int[length];dp[0] = nums[0];dp[1] = Math.max(nums[0], nums[1]);for (int i = 2; i < length; i++) {dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);}return dp[length - 1];}}
官方没有JS的答案,不过思路都是一样的,就是用一个数组来保存状态从而避免递归的使用。
所以我重写了一下:
var rob = function(nums) {if(nums.length == 0||nums==null)return 0;if(nums.length == 1) return nums[0];var dp = new Array();dp[0] = nums[0];dp[1] = Math.max(nums[0],nums[1]);for(let i = 2;i<nums.length;i++){dp[i] = Math.max(nums[i]+dp[i-2],dp[i-1]);}return dp[nums.length-1];};
三角形最小路径和

思路:
遍历行列,计算每个数据的最小路径,用二维数组记录,通过动态规划来得到最小值。最后再遍历一遍最后一行的数据,把最小的值返回。和上一题思路差不多,不过动用到二维数组相对复杂一点。
var minimumTotal = function(triangle) {if(triangle.length==0||triangle==null)return 0;if(triangle.length == 1)return triangle[0][0];let length = triangle.length;let len = triangle.lengthlet len2 = triangle[len - 1].lengthlet dp = new Array(len).fill('').map(item => new Array(len2))//创建二维数组dp[0][0] = triangle[0][0];dp[1][0] = dp[0][0]+triangle[1][0];dp[1][1] = dp[0][0]+triangle[1][1];for(let i = 2;i<length;i++){dp[i][0] = dp[i-1][0]+triangle[i][0];//计算第一个的dpfor(let j = 1;j<i;j++){dp[i][j] = Math.min(dp[i-1][j]+triangle[i][j],dp[i-1][j-1]+triangle[i][j]);}dp[i][i] = dp[i-1][i-1]+triangle[i][i];//计算最后一个的dp}var out = dp[length-1][0];for(let i =1;i<dp[length-1].length;i++){out = Math.min(out,dp[length-1][i]);}return out;};
提交结果:
这个结果明显很差劲啊,我们来看看更好的解法。
class Solution {public:int minimumTotal(vector<vector<int>>& triangle) {vector<int> dp(triangle.back());for(int i = triangle.size() - 2; i >= 0; i --)for(int j = 0; j <= i; j ++)dp[j] = min(dp[j], dp[j + 1]) + triangle[i][j];return dp[0];}};
这是自下而上的算法,triangle.back是取triangle最后一行来给dp初始化的,通过遍历,最小的数值最终会落到dp[0]里面。
跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
#include <iostream>using namespace std;int res[100];int tmp = 1000000007;int Max = 2;int dp(int n){if(n <= Max){return res[n];//如果有存储就直接返回结果}else{res[n] = (dp(n-1) + dp(n-2))%tmp;//动态规划Max = n;}return res[n];}int main(){int n;res[0] = 0;res[1] = 1;res[2] = 2;//前三级台阶while(cin>>n){//一旦有输入就输出结果cout<<dp(n)<<endl;}return 0;}

