打家劫舍
定义dp数组:考虑下标i(可以偷第i家也可以不偷,只是考虑),则dp[i]表示考虑第i家以及按照规则之前所能够偷到的最大的金额。
定义递推公式:
1.考虑下标i: dp[i - 2] + nums[i];
2.不考虑下标i:dp[i - 1]
dp[i] = max(dp[i - 2] + nums[i], dp[i - 1])
初始化:
dp[0] = nums[0]
dp[1] = max(nums[0], nums[1])
遍历顺序:
从i为2开始遍历,直到遍历至nums数组的最后一个元素。
leetcode 198 打家劫舍
class Solution {
public int rob(int[] nums) {
if(nums.length == 1){
return nums[0];
}
//定义dp数组
int[] dp = new int[nums.length];
//初始化dp数组
dp[0] = nums[0];
dp[1] = Math.max(nums[0], nums[1]);
//递推公式以及遍历顺序
for(int i = 2; i < nums.length; i++){
dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);
}
return dp[nums.length - 1];
}
}
leetcode 213 打家劫舍2
在打家劫舍1的基础之上,将所有的房屋都连成一个环。
分为3种情况讨论:
1.不考虑首位元素。(相当于打家劫舍1)
2.只考虑首元素但不考虑尾元素
3.只考虑尾元素不考虑首元素
其中情况2与情况3均包含了情况1。所以我们只需分别利用打家劫舍1去求解情况2与3,再取最大值即可。
public int robHelper(int[] nums){
//特判
if(nums.length == 1){
return nums[0];
}
//定义以及初始化dp数组
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(dp[i - 1], nums[i] + dp[i - 2]);
}
return dp[nums.length - 1];
}
public int rob(int[] nums) {
//特判
if(nums.length == 1){
return nums[0];
}
//1.只考虑首元素,不考虑尾元素
int[] nums1 = new int[nums.length - 1];
for(int i = 0; i < nums1.length; i++){
nums1[i] = nums[i];
}
//2.只考虑尾元素,不考虑首元素
int[] nums2 = new int[nums.length - 1];
for(int i = 0; i < nums2.length; i++){
nums2[i] = nums[i + 1];
}
return Math.max(robHelper(nums1), robHelper(nums2));
}
}
leetcode 337 打家劫舍3
本题是树形dp问题。
定义dp数组:dp[0]表示不偷当前节点所能获得的最大值,dp[1]表示偷当前节点所能获得的最大值。每个节点都会维护自己的dp数组。
遍历顺序:采用后序遍历。最后返回的根节点的dp数组携带了遍历其左右子树后所能获取的最大值的情况。同时其也考虑了偷与不偷根节点所能获得的最大值的情况。
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int[] robHelper(TreeNode cur){
int[] dp = new int[2];
//分别定义左右节点的dp数组,下标0表示不偷当前节点得到的最大值,下标1表示偷当前节点得到的最大值
int[] leftdp = new int[2];
int[] rightdp = new int[2];
//递归终止的条件
if(cur == null){
return leftdp;
}
//采用后续遍历
leftdp = robHelper(cur.left);
rightdp = robHelper(cur.right);
//处理单层递归的逻辑
int val1 = cur.val + leftdp[0] + rightdp[0];//偷当前节点,则其左右节点都不能偷
int val2 = Math.max(leftdp[0], leftdp[1]) + Math.max(rightdp[0], rightdp[1]);//不偷当前节点
dp[0] = val2;
dp[1] = val1;
return dp;
}
public int rob(TreeNode root) {
//特判
if(root.left == null && root.right == null){
return root.val;
}
int[] res = new int[2];
res = robHelper(root);
return Math.max(res[0], res[1]);
}
}