LeetCode 198. 打家劫舍 House Robber
阿新 • • 發佈:2018-11-12
9-4 狀態的定義和狀態轉移 House Robber
題目: LeetCode 198. 打家劫舍
你是一個專業的小偷,計劃偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。
給定一個代表每個房屋存放金額的非負整數陣列,計算你在不觸動警報裝置的情況下,能夠偷竊到的最高金額。
示例 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 。
其中對“狀態”的定義:考慮偷取[x, n-1]範圍裡的房子(函式的定義)。
根據對狀態的定義,決定狀態的轉移:
f(0) = max{v(0) + f(2), v(1) + f(3), v(2) + f(4), …, v(n-3) + f(n-1), v(n-2) , v(n-1) }
import java.util.Arrays;
/// 198. House Robber
/// https://leetcode.com/problems/house-robber/description/
/// 記憶化搜尋
/// 時間複雜度: O(n^2)
/// 空間複雜度: O(n)
public class Solution1 {
// memo[i] 表示考慮搶劫 nums[i...n) 所能獲得的最大收益
private int[] memo;
public int rob(int[] nums) {
memo = new int[nums.length];
Arrays.fill(memo, -1);
return tryRob (nums, 0);
}
// 考慮搶劫nums[index...nums.size())這個範圍的所有房子
private int tryRob(int[] nums, int index){
if(index >= nums.length)
return 0;
if(memo[index] != -1)
return memo[index];
int res = 0;
for(int i = index ; i < nums.length ; i ++)
res = Math.max(res, nums[i] + tryRob(nums, i + 2));
memo[index] = res;
return res;
}
public static void main(String[] args) {
int nums[] = {2, 1};
System.out.println((new Solution1()).rob(nums));
}
}
import java.util.Arrays;
/// 198. House Robber
/// https://leetcode.com/problems/house-robber/description/
/// 動態規劃
/// 時間複雜度: O(n^2)
/// 空間複雜度: O(n)
public class Solution2 {
public int rob(int[] nums) {
int n = nums.length;
if(n == 0)
return 0;
// memo[i] 表示考慮搶劫 nums[i...n) 所能獲得的最大收益
int[] memo = new int[nums.length];
memo[n - 1] = nums[n - 1];
for(int i = n - 2 ; i >= 0 ; i --)
for (int j = i; j < n; j++)
memo[i] = Math.max( memo[i],
nums[j] + (j + 2 < n ? memo[j + 2] : 0));
return memo[0];
}
public static void main(String[] args) {
int nums[] = {2, 1};
System.out.println((new Solution2()).rob(nums));
}
}
import java.util.Arrays;
/// 198. House Robber
/// https://leetcode.com/problems/house-robber/description/
/// 記憶化搜尋, 改變狀態定義
/// 時間複雜度: O(n^2)
/// 空間複雜度: O(n)
public class Solution3 {
// memo[i] 表示考慮搶劫 nums[0...i] 所能獲得的最大收益
private int[] memo;
public int rob(int[] nums) {
memo = new int[nums.length];
Arrays.fill(memo, -1);
return tryRob(nums, nums.length - 1);
}
// 考慮搶劫nums[0...index]這個範圍的所有房子
private int tryRob(int[] nums, int index){
if(index < 0)
return 0;
if(memo[index] != -1)
return memo[index];
int res = 0;
for(int i = 0 ; i <= index ; i ++)
res = Math.max(res, nums[i] + tryRob(nums, i - 2));
memo[index] = res;
return res;
}
public static void main(String[] args) {
int nums[] = {2, 1};
System.out.println((new Solution3()).rob(nums));
}
}
/// 198. House Robber
/// https://leetcode.com/problems/house-robber/description/
/// 動態規劃, 改變狀態定義
/// 時間複雜度: O(n^2)
/// 空間複雜度: O(n)
public class Solution4 {
public int rob(int[] nums) {
int n = nums.length;
if(n == 0)
return 0;
// memo[i] 表示考慮搶劫 nums[0...i] 所能獲得的最大收益
int[] memo = new int[nums.length];
memo[0] = nums[0];
for(int i = 1 ; i < n ; i ++)
for (int j = i; j >= 0; j--)
memo[i] = Math.max(memo[i],
nums[j] + (j - 2 >= 0 ? memo[j - 2] : 0));
return memo[n-1];
}
public static void main(String[] args) {
int nums[] = {2, 1};
System.out.println((new Solution4()).rob(nums));
}
}
import java.util.Arrays;
/// 198. House Robber
/// https://leetcode.com/problems/house-robber/description/
/// 記憶化搜尋, 優化狀態轉移
/// 時間複雜度: O(n)
/// 空間複雜度: O(n)
public class Solution5 {
// memo[i] 表示考慮搶劫 nums[i...n) 所能獲得的最大收益
private int[] memo;
public int rob(int[] nums) {
memo = new int[nums.length];
Arrays.fill(memo, -1);
return tryRob(nums, 0);
}
// 考慮搶劫nums[index...nums.size())這個範圍的所有房子
private int tryRob(int[] nums, int index){
if(index >= nums.length)
return 0;
if(memo[index] != -1)
return memo[index];
// 或者當前房子放棄, 從下一個房子開始考慮
// 或者搶劫當前的房子, 從i+2以後的房子開始考慮
return memo[index] =
Math.max(tryRob(nums, index + 1),
nums[index] + tryRob(nums, index + 2));
}
public static void main(String[] args) {
int nums[] = {2, 1};
System.out.println((new Solution5()).rob(nums));
}
}
import java.util.Arrays;
/// 198. House Robber
/// https://leetcode.com/problems/house-robber/description/
/// 動態規劃, 優化狀態轉移
/// 時間複雜度: O(n)
/// 空間複雜度: O(n)
public class Solution6 {
public int rob(int[] nums) {
int n = nums.length;
if(n == 0)
return 0;
// memo[i] 表示考慮搶劫 nums[i...n) 所能獲得的最大收益
int[] memo = new int[nums.length];
memo[n - 1] = nums[n - 1];
for(int i = n - 2 ; i >= 0 ; i --)
// 或者當前房子放棄, 從下一個房子開始考慮
// 或者搶劫當前的房子, 從i+2以後的房子開始考慮
memo[i] = Math.max(memo[i + 1],
nums[i] + (i + 2 < n ? memo[i + 2] : 0));
return memo[0];
}
public static void main(String[] args) {
int nums[] = {2, 1};
System.out.println((new Solution6()).rob(nums));
}
}
import java.util.Arrays;
/// 198. House Robber
/// https://leetcode.com/problems/house-robber/description/
/// 記憶化搜尋, 改變狀態定義, 優化轉移方程
/// 時間複雜度: O(n)
/// 空間複雜度: O(n)
public class Solution7 {
// memo[i] 表示考慮搶劫 nums[0...i] 所能獲得的最大收益
private int[] memo;
public int rob(int[] nums) {
memo = new int[nums.length];
Arrays.fill(memo, -1);
return tryRob(nums, nums.length - 1);
}
// 考慮搶劫nums[0...index]這個範圍的所有房子
private int tryRob(int[] nums, int index){
if(index < 0)
return 0;
if(memo[index] != -1)
return memo[index];
// 或者當前房子放棄, 考慮[0...index-1]的所有房子
// 或者搶劫當前的房子, 考慮[0...index-2]的所有房子
return memo[index] =
Math.max(tryRob(nums, index - 1),
nums[index] + tryRob(nums, index - 2));
}
public static void main(String[] args) {
int nums[] = {2, 1};
System.out.println((new Solution7()).rob(nums));
}
}
/// 198. House Robber
/// https://leetcode.com/problems/house-robber/description/
/// 動態規劃, 改變狀態定義, 優化轉移方程
/// 時間複雜度: O(n)
/// 空間複雜度: O(n)
public class Solution8 {
public int rob(int[] nums) {
int n = nums.length;
if(n == 0)
return 0;
// memo[i] 表示考慮搶劫 nums[0...i] 所能獲得的最大收益
int[] memo = new int[nums.length];
memo[0] = nums[0];
for(int i = 1 ; i < n ; i ++)
memo[i] = Math.max(memo[i - 1],
nums[i] + (i - 2 >= 0 ? memo[i - 2] : 0));
return memo[n-1];
}
public static void main(String[] args) {
int nums[] = {2, 1};
System.out.println((new Solution8()).rob(nums));
}
}