leetcode-zgd-day48-198.打家劫舍/213.打家劫舍II/337.打家劫舍III

125 阅读2分钟

198.打家劫舍

题目链接:198. 打家劫舍 - 力扣(LeetCode)

解题思路:

因为不能偷两个相邻的房间,偷到当前房间能偷的最大价值就转化成了两种情况:

1.偷第i个房间,那么第i-1个房间肯定就不能偷了,当前情况的最大价值就是偷到i-2房间的最大价值+当前房间的财产价值。

2.不偷第i个房间,那么第i-1个房间可以偷,所以当前情况的最大价值就是偷到i-1房间的最大价值。

 class Solution {
     public int rob(int[] nums) {
         /**
          * dp[i] 从下标0偷到下标j能偷的最大金额
          * dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i])
          */
         if(nums.length == 1) return nums[0];
         int[] dp = new int[nums.length + 1];
         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]);
             for(int k = 0; k < dp.length; k++){
                 System.out.print(dp[k] + " ");
             }
             System.out.println();
         }
         return dp[nums.length - 1];
     }
 }

213.打家劫舍II

题目链接:213. 打家劫舍 II - 力扣(LeetCode)

解题思路:

 class Solution {
     public int rob(int[] nums) {
         /**
          * 该问题可以分为两种情况考虑,因为房子是一个环,第一个房间和最后一个房间不可能同时偷,所以分为一下两种情况:
          * 1.偷第一个房子,最后一个房子肯定不偷了,直接将其剔除
          * 2.偷最后一个房子,第一个房子肯定不偷了,将其剔除
          * 后续两种情况分别按照打家劫舍I处理即可。
          * dp[i] 前j个房子能偷的最大金额
          * dp[i] = Math.maxx(dp[i - 1], dp[i - 2] + nums[i]);
          * dp[start] = nums[start]
          * dp[start + 1] = Math.max(nums[start], nums[start + 1])
          */
         if(nums.length == 1) return nums[0];
         int hasStart = maxprice(nums,0,nums.length - 2);
         int hasEnd = maxprice(nums, 1, nums.length - 1);
         return Math.max(hasEnd,hasStart);
     }
     public int maxprice(int[] nums, int startIndex, int endIndex){
         if(startIndex == endIndex) return nums[startIndex];
         int[] dp = new int[nums.length + 1];
         dp[startIndex] = nums[startIndex];
         dp[startIndex + 1] = Math.max(nums[startIndex], nums[startIndex + 1]);
         for(int i = startIndex + 2; i <= endIndex; i++){
             dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
         }
         return dp[endIndex];
     }
 }

337.打家劫舍III

题目链接:337. 打家劫舍 III - 力扣(LeetCode)

解题思路:

这个题有很多点需要注意和学习,需要多次复习。

递归写法,这种类型返回值的递归要好好留意。

 class Solution {
     public int rob(TreeNode root) {
         /**
          * 第一次接触树形结构的dp,有点懵逼
          * 状态标记递归写法,当递归想要返回多个值的时候,可以考虑返回一个数组
          */
         List<Integer> record = maxPrice(root);
         return Math.max(record.get(0),record.get(1));
     }
     List<Integer> maxPrice(TreeNode root){
         if(root == null) return Arrays.asList(0,0);
         // 自底向上,后序遍历
         List<Integer> left = maxPrice(root.left); // 左
         List<Integer> right = maxPrice(root.right); // 右
         // 中
         int val1 = 0, val2 = 0; // 1:偷 2:不偷
         val1 = root.val + left.get(1) + right.get(1);
         val2 += Math.max(left.get(0),left.get(1)) + Math.max(right.get(0), right.get(1));
         return Arrays.asList(val1,val2);
     }
 }

注意两种不同返回方式的写法,int[]和ArrayList()

 class Solution {
     public int rob(TreeNode root) {
         /**
          * 第一次接触树形结构的dp,有点懵逼
          * 状态标记递归写法,当递归想要返回多个值的时候,可以考虑返回一个数组
          */
         int[] record = maxPrice(root);
         return Math.max(record[0],record[1]);
     }
     int[] maxPrice(TreeNode root){
         if(root == null) return new int[]{0,0};
         // 自底向上,后序遍历
         int[] left = maxPrice(root.left); // 左
         int[] right = maxPrice(root.right); // 右
         // 中
         int val1 = 0, val2 = 0; // 1:偷 2:不偷
         val1 = root.val + left[1] + right[1];
         val2 += Math.max(left[0],left[1]) + Math.max(right[0], right[1]);
         return new int[]{val1,val2};
     }
 }

记忆化递归,其实就是用一个Map来存储已经计算过的根节点对应的值,避免重复计算。

 class Solution {
     public int rob(TreeNode root) {
         /**
          * 记忆化递归
          */
         Map<TreeNode,Integer> record = new HashMap<>();
         int ans = maxPrice(root, record);
         return ans;
     }
     int maxPrice(TreeNode root, Map<TreeNode, Integer> record){
         if(root == null) return 0;
         if(record.containsKey(root)) return record.get(root);
 ​
         int val1 = 0, val2 = root.val;
         // 偷
         if(root.left != null) val2 += maxPrice(root.left.right,record) + maxPrice(root.left.left,record);
         if(root.right != null) val2 += maxPrice(root.right.left,record) + maxPrice(root.right.right,record);
         // 不偷
         val1 = maxPrice(root.left,record) + maxPrice(root.right,record);
         int ans = Math.max(val1, val2);
         record.put(root,ans);
         return ans;
     }
 }