*LeetCode--198. 213. House Robber(入室强盗)
198 House Robber
问题大意:
一个强盗打算抢一条街上的若干户人家,每一家都有一定数量的财物。由于存在这样一种报警机制:如果强盗抢了两户相邻的人家,那么就会自动报警。在这种情况下,强盗怎么抢才能使得收益最大。
使用一个数组来表示每一户拥有的财物。
方法1:采用递归的方法(超时了)
第一步一定会选取nums[0]或者nums[1],即start=0或1,否则最终的结果不是最大的。
递归:对nums[start+2]之后的元素和nums[start+3]之后的元素分别进行递归,结果为nums[start]+fun(nums,start+2) 和 nums[start]+fun(nums,start+3),二者的最大值就是最大的收益。
代码:
public static int rob(int[] nums) { if(nums.length==0) return 0; System.out.println(nums.length); return getMaxMoney(nums,0); } public static int getMaxMoney(int[] nums , int start){ int len = nums.length; if(start == len-1) return nums[len-1]; if(start == len-2) return Math.max(nums[len-1],nums[len-2]); int sum1 = nums[start]; if(start+2<len) sum1 = nums[start] + getMaxMoney(nums,start+2); int sum2 = nums[start+1]; if(start+3<len) sum2 = nums[start+1] + getMaxMoney(nums , start+3); return Math.max(sum1, sum2); }
提交后运行超时。
方法2:动态规划
使用maxv[i]表示从第0个房子到第i个房子的最大收益。
对于第n个房间我们所能有的选择是偷和不偷, 那么如果是做决定是偷 则上一步必须是不偷,此时的收益是:maxv[i-2]+nums[i]
如果是不偷, 那么上一步就无所谓是不是已经偷过,此时的收益是:maxv[i-1]
递推关系:maxv[i] = Math.max(maxv[i-1], maxv[i-2]+nums[i]);
public static int rob(int[] nums) { int len = nums.length; if(len == 0) return 0; if(len == 1) return nums[0]; int[] maxv = new int[len]; maxv[0] = nums[0]; maxv[1] = Math.max(nums[0],nums[1]); for(int i = 2 ; i < len ; i++){ maxv[i] = Math.max(maxv[i-1], maxv[i-2]+nums[i]); //如果不抢第i户,那么直接用maxv[i-1],不用在意i-1户被没被抢; 如果抢这一户,则为maxv[i-2]+nums[i] } return maxv[len-1]; }
213 House Robber II
对于House Robber II,基本和原来类似,只是变为首尾连接的。就是最后一户和第一户是相邻的,在这种情况下求最大收益。
方法:仍然利用动态规划,和原来的类似。
假设nums数组从0到k,那么求n到K-1 和 1到k这两者的的最大值 求法同原来的HouseRobber不相邻的情况。
public static int rob(int[] nums) { int len = nums.length; if(len==0) return 0; if(len==1) return nums[0]; return Math.max(helper(nums,0,len-1),helper(nums,1,0)); } public static int helper(int[] nums, int start , int end){ int p = 0, q = 0; for (int i = start; i != end; /* do nothing */) { int tmp = p; p = Math.max(p, q + nums[i]); q = tmp; i = (i + 1) % nums.length; } return p; }
另一种方法,对原来House Robber的改进
public static int rob(int[] nums) { int len = nums.length; if(len==0) return 0; if(len==1) return nums[0]; if(len==2) return Math.max(nums[0], nums[1]); return Math.max(helper(nums,0,len-1),helper(nums,1,0)); } public static int helper(int[] nums, int start , int end){ int len = nums.length ; int[] maxv = new int[len]; maxv[start] = nums[start]; //只有第一个元素情况下的最大值 maxv[start+1] = Math.max(nums[start],nums[start+1]); //只有前两个元素情况下的最大值 for(int i = (start+2+len)%len ;i != end; ){ System.out.println(i); maxv[i] = Math.max(maxv[(i+len-1)%len], maxv[(i+len-2)%len]+nums[i]); i = (i+1)%(len); } return maxv[(end-1+len)%len]; }

浙公网安备 33010602011771号