leetcode-198 打家劫舍
你是一個專業的小偷,計劃偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。
給定一個代表每個房屋存放金額的非負整數陣列,計算你在不觸動警報裝置的情況下,能夠偷竊到的最高金額。
示例 1:
輸入: [1,2,3,1] 輸出: 4 解釋: 偷竊 1 號房屋 (金額 = 1) ,然後偷竊 3 號房屋 (金額 = 3)。 偷竊到的最高金額 = 1 + 3 = 4 。
思路:動態規劃
我們維護一個一位陣列dp,其中dp[i]表示到i位置時不相鄰數能形成的最大和,那麼狀態轉移方程怎麼寫呢,我們先拿一個簡單的例子來分析一下,比如說nums為{3, 2, 1, 5},那麼我們來看我們的dp陣列應該是什麼樣的,首先dp[0]=3沒啥疑問,再看dp[1]是多少呢,由於3比2大,所以我們搶第一個房子的3,當前房子的2不搶,所以dp[1]=3,那麼再來看dp[2],由於不能搶相鄰的,所以我們可以用再前面的一個的dp值加上當前的房間值,和當前房間的前面一個dp值比較,取較大值當做當前dp值,所以我們可以得到狀態轉移方程dp[i] = max(num[i] + dp[i - 2], dp[i - 1]), 由此看出我們需要初始化dp[0]和dp[1],其中dp[0]即為num[0],dp[1]此時應該為max(num[0], num[1])。
public int rob(int[] nums) { if(nums.length <= 1) return nums.length == 0 ? 0 : nums[0]; int[] dp = new int[nums.length]; dp[0] = nums[0]; dp[1] = Math.max(nums[0], nums[1]); for(int i = 2; i < nums.length; i++){ dp[i] = Math.max(nums[i] + dp[i - 2], dp[i - 1]); } return dp[nums.length - 1]; }
根據奇偶位置
分別維護兩個變數robEven和robOdd,顧名思義,robEven就是要搶偶數位置的房子,robOdd就是要搶奇數位置的房子。所以我們在遍歷房子陣列時,如果是偶數位置,那麼robEven就要加上當前數字,然後和robOdd比較,取較大的來更新robEven。這裡我們就看出來了,robEven組成的值並不是只由偶數位置的數字,只是當前要搶偶數位置而已。同理,當奇數位置時,robOdd加上當前數字和robEven比較,取較大值來更新robOdd,這種按奇偶分別來更新的方法,可以保證組成最大和的數字不相鄰,最後別忘了在robEven和robOdd種取較大值返回。
public int rob(int[] nums) {
int robEven = 0;
int robOdd = 0;
int n = nums.length;
for(int i = 0; i < n ; i++){
if(i % 2 == 0){
robEven = Math.max(robEven + nums[i], robOdd);
}else{
robEven = Math.max(robOdd + nums[i], robEven);
}
}
return Math.max(robEven, robOdd);
}