1. 程式人生 > >leetcode-198-打家劫舍(house robber)-java

leetcode-198-打家劫舍(house robber)-java

題目及用例

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(成功,6ms,較快)
如果nums只有一個,返回那一個
如果2個,返回中間大的那個
之後
現在i的max=max( (i-2)的max+num[i] ,(i-1)的max)
用動態規劃,不斷max上去

package pid198;


class Solution {
	 public int rob(int[] nums) {
	 int length=nums.length;
	 
	 if(length==0){
		 return 0;
	 }
	 if(length==1){
		 return nums[0];
	 }
	 if(length==2){
		 return nums[0]>nums[1]?nums[0]:nums[1];
	 }
	 int sumOne=nums[0];
	 int sumTwo=nums[0]>nums[1]?nums[0]:nums[1];
	 int sumNow=0;
	 // [1,2,3,1]
	 //3 此處的max 為1的max+3 與2的max 中的max
	 for(int i=2;i<length;i++){
		 sumNow=sumOne+nums[i]>sumTwo?sumOne+nums[i]:sumTwo;
		 sumOne=sumTwo;
		 sumTwo=sumNow;
	 }
		 
		 
	 return sumNow;
	  }
}

解法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];
    }
}