题型一:
打家劫舍
思路:
递归:
当我们计算如果有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.length
let len2 = triangle[len - 1].length
let 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];//计算第一个的dp
for(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]里面。