你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例 1:
输入: [1,2,3,1]
输出: 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 。
动态规划思路:最重要的就是
1.定义目前的一个状态,这个状态就是大问题的子问题的函数表现形式,(这里就是number[i]是当前找到的i个房子不报警条件下的最大值).
2.转移方程,其实我觉得就是根据题目从(number[i]到number[i+1]的求解过程,构造成函数表现形式)
number[i] = Math.max(number[i-2]+nums[i],number[i-1])
3.根据前2个条件,把一些边界情况考虑清楚。(因为动态规划是从自底向上的求解,所以边界条件的思考正确与否代表你能否得到正确的答案,我认为挺重要的)
number[0=nums[0]
number[1]=Math.max(nums[0],nums[1])这里number[1]其实就是做出了第一次的决策过程。
假设如果是number[1]为当前选择的起点,当我们选择number[2]时又怎么选呢?根据转移方程其实number[i]=Math.max(number[i-2]+nums[i],number[i-1])中的最大值,可是题干给的意思不能相邻啊?这个时候就是状态的定义问题了,你定义的好,问题很明显,定义不好,那么问题就会变复杂。这里的状态是当前找到的房子i不报警条件下的最大值,当number[3]等于啥,等于从i-2隔着的条件下或者i-1中选择最大的值(选择n-1时,就代表着当前n不选择)满足题意
public int rob(int[] nums) {
if(nums==null||nums.length<=0){
return 0;
}
int total = nums.length;
int[] number = new int[nums.length];
if(nums.length==1){
return nums[0];
}
if(nums.length==2){
Math.max(nums[0],nums[1]);
}
number[0] = nums[0];
//这里忽略了原始条件对初始值的影响
number[1] = Math.max(nums[0],nums[1]);
for(int i=2;i<total;i++){
if(number[i-2]+nums[i]>(number[i-1]))
number[i] = number[i-2]+nums[i];
else
number[i] = number[i-1];
}
return Math.max(number[total-1],number[total-2]);
}