打家劫舍
状态方程:dp[i]=max{ dp[i-k]+nums[i] } 其中2<=k<=i; 需要注意初始化和一些边界条件
public int rob(int[] nums) {
if(nums.length==1)return nums[0];
int[] dp=new int[nums.length];
dp[0]=nums[0];
dp[1]=Math.max(nums[0], nums[1]);
int max=dp[1];
for(int i=2; i<nums.length; i++) {
for(int k=2; k<=i; k++) {
//因为每次不确定是隔几个人偷能达到最大值,所以要遍历可能的情况
//并且不能用滚动数组去降维,因为dp[i]和dp[i-1]之前的状态有关,而不仅仅是和dp[i-1]
max=Math.max(dp[i-k]+nums[i], max);
}
dp[i]=max;
}
return dp[nums.length-1];
}
时间复杂度高了:
public int rob(int[] nums) {
if(nums.length==1)return nums[0];
if(nums.length==2)return Math.max(nums[0], nums[1]);
int[] dp=new int[nums.length]; //前i家的最大打劫值
dp[0]=nums[0];
dp[1]=Math.max(nums[0], nums[1]);
for(int i=2; i<nums.length; i++) {
dp[i]=Math.max(dp[i-1], dp[i-2]+nums[i]);
}
return dp[nums.length-1];
}
打家劫舍2
思想:把环拆成两个队列,一个是从0到n-1,另一个是从1到n,然后返回两个结果最大的。
public int rob(int[] nums) {
if(nums.length==1)return nums[0];
if(nums.length==2)return Math.max(nums[0], nums[1]);
int[] dp=new int[nums.length];
dp[0]=nums[0];
dp[1]=Math.max(nums[0], nums[1]);
int max=dp[1];
//0~n-1
for(int i=2; i<nums.length-1; i++) {
for(int k=2; k<=i; k++) {
max=Math.max(dp[i-k]+nums[i], max);
}
dp[i]=max;
}
int[] db=new int[nums.length];
db[1]=nums[1];
db[2]=Math.max(nums[1], nums[2]);
max=db[1];
//1~n
for(int i=3; i<=nums.length-1; i++) {
for(int k=2; k<=i; k++) {
max=Math.max(db[i-k]+nums[i], max);
}
db[i]=max;
}
return Math.max(dp[nums.length-2], db[nums.length-1]);
}
打家劫舍3
之后来填坑