随想录日记part38
t i m e : time: time: 2024.04.07
主要内容:今天开始要学习动态规划的相关知识了,今天的内容主要涉及:
打家劫舍。
动态规划五部曲:
【1】.确定dp数组以及下标的含义
【2】.确定递推公式
【3】.dp数组如何初始化
【4】.确定遍历顺序
【5】.举例推导dp数组
Topic1打家劫舍
题目:
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
输入: [ 1 , 2 , 3 , 1 ] [1,2,3,1] [1,2,3,1]
输出: 4 4 4
思路:
接下来进行动规五步曲:
1.确定dp数组以及下标的含义:
dp[i]:考虑下标i(包括i)以内的房屋,最多可以偷窃的金额为dp[i];
2.确定递推公式:
dp[i] = max(dp[i - 2] + nums[i], dp[i - 1])
3.dp数组如何初始化
dp[0]=nums[0];dp[1]=Math.max(nums[0],nums[1]);
4.确定遍历顺序
5.举例推导dp数组
代码如下:
class Solution {
public int rob(int[] nums) {
int[] dp=new int[nums.length];
if(nums.length==1) return nums[0];
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],dp[i-2]+nums[i]);
}
return dp[nums.length-1];
}
}
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)
Topic2打家劫舍II
题目:
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。
输入: n u m s = [ 2 , 3 , 2 ] nums = [2,3,2] nums=[2,3,2]
输出: 3 3 3
解释:
你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
思路:
对于一个数组,成环的话主要有如下三种情况:
情况一:考虑不包含首尾元素
情况二:考虑包含首元素,不包含尾元素
情况三:考虑包含尾元素,不包含首元素
其他思路同上:
整体代码如下:
class Solution {
public int rob(int[] nums) {
if(nums.length==1) return nums[0];
if(nums.length==2) return Math.max(nums[0],nums[1]);
int result1=rob1(nums,0,nums.length-2);
int result2=rob1(nums,1,nums.length-1);
return Math.max(result1,result2);
}
public int rob1(int[] nums,int start,int end) {
int[] dp=new int[nums.length];
if(start==end) return nums[start];
dp[start]=nums[start];
dp[start+1]=Math.max(nums[start],nums[start+1]);
for(int i=start+2;i<=end;i++){
dp[i]=Math.max(dp[i-1],dp[i-2]+nums[i]);
}
return dp[end];
}
}
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)
Topic3打家劫舍|||
题目:
小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。
除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。给定二叉树的 root 。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。
输入: r o o t = [ 3 , 2 , 3 , n u l l , 3 , n u l l , 1 ] root = [3,2,3,null,3,null,1] root=[3,2,3,null,3,null,1]
输出: 7 7 7
思路:
代码中给出核心解释
代码如下:
/**
* 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 rob(TreeNode root) {
int[] res=new int[2];
res=rob1(root);
return Math.max(res[1],res[0]);
}
// 3.状态标记递归
// 执行用时:0 ms , 在所有 Java 提交中击败了 100% 的用户
// 不偷:Max(左孩子不偷,左孩子偷) + Max(右孩子不偷,右孩子偷)
// root[0] = Math.max(rob(root.left)[0], rob(root.left)[1]) +
// Math.max(rob(root.right)[0], rob(root.right)[1])
// 偷:左孩子不偷+ 右孩子不偷 + 当前节点偷
// root[1] = rob(root.left)[0] + rob(root.right)[0] + root.val;
private int[] rob1(TreeNode root){
int[] res=new int[2];
if(root==null) return res;
int[] left=rob1(root.left);
int[] right=rob1(root.right);
res[0]=Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
res[1]=root.val + left[0] + right[0];
return res;
}
}
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( l o g n ) O(log n) O(logn)