198. 打家劫舍
思路一:
- dp[i]表示洗劫第i家能获得的最大收益。
- tmp用来表示[0,i-2]中能获得的最大收益。
d p [ i ] = n u m s [ i ] + m a x j ∈ [ 0 , i − 2 ] ( d p [ j ] ) r e s = m a x i ∈ [ 0 , n ] d p [ i ] dp[i]=nums[i]+max_{j\in[0,i-2]}(dp[j]) \\ res = max_{i \in [0,n]} dp[i] dp[i]=nums[i]+maxj∈[0,i−2](dp[j])res=maxi∈[0,n]dp[i]
class Solution {
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[] dp = new int[nums.length]; // dp[i]表示洗劫第i家最大能获得的收益
dp[0] = nums[0];
dp[1] = nums[1];
int res = Math.max(dp[0],dp[1]);
int tmp = dp[0]; // 用来记录[0,i-2]最多赚的钱
for(int i=2;i<nums.length;i++){
dp[i] = tmp+nums[i];
tmp = Math.max(tmp,dp[i-1]);
res = Math.max(res,dp[i]);
}
return res;
}
}
思路二:
- dp[i]表示洗劫[0,i]中能获得的最大收益
- 情况一:抢第i家
- dp[i] = nums[i] + dp[i-2]
- 这里有一个问题是dp[i-1]只是说[0,i-1]中能获得的最大收益,并未说明我们一定偷了第i-1家。但这种担心是多余的
- 假设我们偷了第i-1家,则我们上面的式子满足要求
- 假设我们没有偷第i-1家,则由情况二:dp[i-1] = dp[i-2],我们上面的式子也满足要求。
- 情况二:不抢第i家
- dp[i] = dp[i-1]
d p [ i ] = m a x ( n u m s [ i ] + d p [ i − 2 ] , d p [ i − 1 ] ) dp[i] = max(nums[i]+dp[i-2],dp[i-1]) dp[i]=max(nums[i]+dp[i−2],dp[i−1])
class Solution {
public int rob(int[] nums) {
int pre = 0, cur = 0, tmp; //pre i-2 cur i-1 tmp nums[i]
for(int num : nums) {
tmp = cur;
cur = Math.max(pre + num, cur);
pre = tmp;
}
return cur;
}
}
213. 打家劫舍 II
思路:
- 关键是我们可以将问题拆分为打劫[0,n-2]和[1,n-1]家,再求两者的最大值。
原因在于:
- 如果我们打劫了0,由于限制条件,剩下能打劫的房屋一定在[2,n-2]中选择了,这一定<[0,n-2]能获得的值。
- 如果我们没有打劫0,由于限制条件,剩下能打劫的房屋一定在[1,n-1]中选择了,这一定<[1,n-1]。
同理对n-1也可以有类似的讨论。
class Solution {
public int rob(int[] nums) {
if(nums.length==1) return nums[0];
return Math.max(aidRob(nums,0,nums.length-1),aidRob(nums,1,nums.length));
}
// dp[i] = max(dp[i-1],dp[i-2]+nums[i])
// tmp = max(cur,pre+num);
public int aidRob(int[] nums,int l, int r){
int pre=0,cur=0,tmp;
for(int i=l;i<r;i++){
tmp = Math.max(cur,pre+nums[i]);
pre = cur;
cur = tmp;
}
return cur;
}
}
337. 打家劫舍 III [树形dp]
- 这里的dp是树形的。
class Solution {
HashMap<TreeNode,Integer> f = new HashMap<>();
HashMap<TreeNode,Integer> g = new HashMap<>();
public int rob(TreeNode root) {
dfs(root);
return Math.max(f.getOrDefault(root,0),g.getOrDefault(root,0));
}
public void dfs(TreeNode root){
if(root == null)
return;
dfs(root.left);
dfs(root.right);
// 先到最底部,一路更新上来
f.put(root,root.val+g.getOrDefault(root.left,0)+g.getOrDefault(root.right,0));
g.put(root,Math.max(f.getOrDefault(root.left,0),g.getOrDefault(root.left,0))+Math.max(f.getOrDefault(root.right,0),g.getOrDefault(root.right,0)));
}
}