原題地址
題目:
假設你是一個專業的竊賊,準備沿着一條街打劫房屋。每個房子都存放着特定金額的錢。你面臨的唯一約束條件是:相鄰的房子裝着相互聯繫的防盜系統,且 當相鄰的兩個房子同一天被打劫時,該系統會自動報警。
給定一個非負整數列表,表示每個房子中存放的錢, 算一算,如果今晚去打劫,你最多可以得到多少錢 在不觸動報警裝置的情況下。
您在真實的面試中是否遇到過這個題? Yes
樣例
給定 [3, 8, 4], 返回 8.
分析:
簡單dp題。當前房屋 i 的最大可達錢取決於dp[i - 2]和dp[i - 3]的最大值(dp[i - 4]的情況屬於dp[i - 2])。
注意返回值要爲long型。
時間複雜度o(n),空間o(n)
public long houseRobber(int[] A) {
long[] dp = new long[A.length];
if (A.length < 1) {
return 0;
}
if (A.length == 1) return A[0];
dp[0] = A[0];
dp[1] = A[1];
long max = Math.max(dp[0], dp[1]);
if (A.length <= 2) {
return max;
}
dp[2] = dp[0] + A[2];
if (dp[2] > max) max = dp[2];
for (int i = 3; i < A.length; i++) {
dp[i] = (dp[i - 2] > dp[i - 3] ? dp[i - 2] : dp[i - 3]) + A[i];
if (dp[i] > max) {
max = dp[i];
}
}
return max;
}
改進的時間複雜度o(n),空間o(1),用dp1和dp2保存dp[i - 3]和dp[i - 2]。
public long houseRobber(int[] A) {
if (A.length < 1) {
return 0;
}
if (A.length < 2) {
return A[0];
}
long dp1 = A[0];
long dp2 = A[1];
long max = Math.max(dp1, dp2);
if (A.length == 2) {
return max;
}
max = (dp1 + A[2]) > dp2 ? (dp1 + A[2]) : dp2;
long temp = max;
long tempLast = temp;
for (int i = 3; i < A.length; i++) {
temp = (dp1 > dp2 ? dp1 : dp2) + A[i];
if(temp > max) max = temp;
dp1 = dp2;
dp2 = tempLast;
tempLast = temp;
}
return max;
}
另外一種思路:
參考網址
用一個二維數組dp[A.length][2],其中對於第i所房子,dp[i][0]表示不打劫i,此時其能獲得的最大錢數爲:
dp[i][0] = max(dp[i - 1][0] ,dp[i - 1][1])
dp[i][1]表示打劫i,其等於不打劫上一家的情況下,再加上i的錢數:
dp[i][1] = dp[i - 1][0] + A[i];
public long houseRobber(int[] A) {
if(A.length==0)
return 0;
long[][] dp = new long[A.length][2];
dp[0][1] = A[0];
for(int i=1;i<A.length;++i){
dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]);
dp[i][1] = dp[i-1][0]+A[i];
}
return Math.max(dp[A.length-1][0],dp[A.length-1][1]);
}