题目及用例
package pid198;
/* 打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例 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 。
*/
public class main {
public static void main(String[] args) {
int[][] testTable = {{1,2,3,1},{2,7,9,3,1},{7,10,4,3,1},{11,6,2,7}};
for (int[] ito : testTable) {
test(ito);
}
}
private static void test(int[] ito) {
Solution solution = new Solution();
int rtn;
long begin = System.currentTimeMillis();
for (int i = 0; i < ito.length; i++) {
System.out.print(ito[i]+" ");
}
System.out.println();
//开始时打印数组
rtn = solution.rob(ito);//执行程序
long end = System.currentTimeMillis();
//System.out.println(ito + ": rtn=" + rtn);
System.out.println( " rtn=" +rtn);
// for (int i = 0; i < ito.length; i++) {
// System.out.print(ito[i]+" ");
// }//打印结果几数组
System.out.println();
System.out.println("耗时:" + (end - begin) + "ms");
System.out.println("-------------------");
}
}
解法1(成功,1ms,超快)
如果nums只有一个,返回那一个
如果2个,返回中间大的那个
之后
现在i的max=max( (i-2)的max+num[i] ,(i-1)的max)
max[i]=max[i-2]+nums[i] / max[i-1]
用动态规划,不断max上去
public int rob(int[] nums) {
//max[i]=max[i-2]+nums[i] / max[i-1]
int length=nums.length;
if(length==0){
return 0;
}
if(length==1){
return nums[0];
}
//即max[i-2]
int prev2=nums[0];
//即max[i-1]
int prev1=nums[0]>nums[1]?nums[0]:nums[1];
for(int i=2;i<length;i++){
int now=nums[i];
int nowMax=prev2+now>prev1?prev2+now:prev1;
prev2=prev1;
prev1=nowMax;
}
return prev1;
}
解法2(别人的)
不优秀
暴力搜索方法
思路:文中给出不能连续抢两家,因此假设从最后一个房屋开始抢,最后一个房屋为index。将原问题分割成子问题,子问题的最优决策可以导出原问题的最优决策。现有两种可能情况,当前房屋抢和当前房屋不抢。若当前房屋抢,则下一房屋不能抢;若当前房屋不抢,则下一房屋可抢;选出这两种情况的最大值,递归执行,直到index<0。
public int solve(int index, int[] nums){
if(index < 0){
return 0;
}
int max = Math.max(nums[index] + solve(index - 2, nums), solve(index - 1, nums));
return max;
}
public int rob(int[] nums) {
return solve(nums.length-1, nums);
}
解法3(别人的)
自顶向下解法
也就是map法,每个的结果都放在数组中
为了避免上述的重复计算,我们初始化一个数组来记录所有记录为-1,如果当前index被算过,就记录下来。因此,每次判断该屋抢还是不抢后,都会得到一个index值。这就是去冗余,用采用空间换时间的方法。因此当n-1房屋的最优解算过后,就能推导出n房屋的最优解。这就是动态规划的思想。
因此,我们考虑使用动态规划,设置result[]数组记录抢夺该房屋可能的最大收益。
class Solution {
public static int[] result;
public int solve(int index, int[] nums){
if(index < 0){
return 0;
}
if(result[index] >= 0){
return result[index];
}
result[index] = Math.max(nums[index] + solve(index-2 , nums), solve(index-1, nums));
return result[index];
}
public int rob(int[] nums) {
result = new int[nums.length];
for(int i=0; i < result.length; i++){
result[i]=-1;
}
return solve(nums.length-1, nums);
}
}
解法4(别人的)
自底向上的map法
public int rob(int[] nums) {
if (nums.length == 0){
return 0;
}
if (nums.length == 1){
return nums[0];
}
if (nums.length == 2){
return Math.max(nums[0], nums[1]);
}
int[] result = new int[nums.length];
result[0] = nums[0];
result[1] = Math.max(nums[0], nums[1]);
for(int index=2; index < result.length; index++){
result[index] = Math.max(nums[index] + result[index-2], result[index -1]);
}
return result[nums.length -1];
}
}