DP:打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例 1:
输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
示例 2:
输入: [2,7,9,3,1]
输出: 12
解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
偷窃到的最高金额 = 2 + 9 + 1 = 12 。
输出: 12
解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
偷窃到的最高金额 = 2 + 9 + 1 = 12 。
具体思路请见leetcode刷题一栏按摩师的解析
因此【动态规划】告诉我们,有些问题可以从最简单的情况考虑,逐步递推,每一步都记住当前问题的答案,即当前最优解。不是直接对问题求解,由于找到了问题最初始的样子,因此在后边的求解过程每一步我们都可以参考之前的结果。
打家劫舍问题(T2)与上楼梯花费体力问题(T1)的不同:
初始化:T2的dp[1]是与dp[0]有关,要么偷家1要么偷家2,哪家多偷哪家,因此dp[1]与取nums[0]与nums[1]的最大;
T1要么从第一阶开始要么从第二阶,两者没有必要联系,就是非此即彼的两种情况,dp[1] = cost[1],dp[0] = cost[0].
过程:T2:1.偷了这家上家就一定不能偷,因此状态就是dp[i-2]+nums[i] 2.这家不偷,上家也可偷可以不偷,状态就是dp[i-1]。最后两者取最大值就是当前最大值。
T1:当前阶层的体力是一定要消耗的,体力消耗最少则取决于上一次是怎么跨越的,是跨越了两阶,还是一阶层,而着两种取最少的就是当前的最小值。
自己说不出所以然,理解只能到这里,还希望大佬指正,学习一下。
1 int rob(int* nums, int numsSize) 2 { 3 int *dp; 4 if(numsSize == 0) 5 return 0; 6 if(numsSize == 1) 7 return nums[0]; 8 dp = (int *)malloc(sizeof(int) * numsSize); 9 dp[0] = nums[0]; 10 dp[1] = nums[1] > nums[0] ? nums[1]:nums[0]; 11 for(int i = 2; i < numsSize; i++) 12 { 13 dp[i] = (nums[i]+dp[i-2]) > dp[i-1] ? (nums[i]+dp[i-2]) : dp[i-1]; 14 } 15 return dp[numsSize - 1]; 16 }