如题
审题,偷了第i家以后是两种可能的做法,偷i+2家或者偷i+3家的,首先用回溯穷举试试
public static void doalone(int idex,int[] nums,int sum,int[]re){
if(idex<nums.length){
sum+=nums[idex];
doalone(idex+2,nums,sum,re);//偷隔一位
doalone(idex+3,nums,sum,re);//偷隔两位
sum-=nums[idex];
}else{
if(sum>re[0]){//与原有最大值比较
re[0]=sum;
}
}
}
很显然当这街道太长会超限
另一种自然是动态规划实现了
对于有i家时的最大值,对于第i家有两种可能,由此推导
if(nums.length==0){
return 0;
}
if(nums.length==1){
return nums[0];
}
int[] []dp = new int[nums.length][2];
dp[0] [0]=0;//第一户不偷
dp[0][1]=nums[0];//第一户偷
dp[1][1]=nums[1];//偷第二户
dp[1][0]=nums[0];//不偷第二户
for(int i=2;i<nums.length;i++){
dp[i][0]=dp[i-1][1]>dp[i-2][1]?dp[i-1][1]:dp[i-2][1];//不偷该户最大为偷前一户最大和前两户最大中的较大值
dp[i][1]=dp[i-1][0]>dp[i-2][1]?dp[i-1][0]+nums[i]:dp[i-2][1]+nums[i];//偷该一户的最大为不偷前一户最大与偷前两户最大中的较大值家当钱户
}
return dp[nums.length-1][0]>dp[nums.length-1][1]?dp[nums.length-1][0]:dp[nums.length-1][1];//偷和不偷的较大值
}
换一种思路,是否可以直接缓存必偷第i家时的最大值呢,那也是可以的
public static int rob2(int[] nums) {
if(nums.length==0){
return 0;
}
if(nums.length==1){
return nums[0];
}
int [] dp =new int[nums.length+2];//缓存偷该家的最大值
dp[0]=nums[0];
dp[1]=nums.length>1?nums[1]:0;
dp[2]=nums.length>2?nums[2]+nums[0]:0;
for(int i=3;i<nums.length;i++){
dp[i]=dp[i-2]>dp[i-3]?dp[i-2]+nums[i]:dp[i-3]+nums[i];//偷第i家的最大值为偷第i-2家与偷第i-3家中的较大值加上该家
}
return dp[nums.length-1]>dp[nums.length-2]?dp[nums.length-1]:dp[nums.length-2];//偷最后一家或者偷倒数第二家的较大值
}
结果倒是相差不大