zoukankan      html  css  js  c++  java
  • LeetCode 337. 打家劫舍 III

    我的LeetCode:https://leetcode-cn.com/u/ituring/

    我的LeetCode刷题源码[GitHub]:https://github.com/izhoujie/Algorithmcii

    LeetCode 337. 打家劫舍 III

    题目

    在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。

    计算在__不触动警报的情况下__,小偷一晚能够盗取的最高金额。
    示例 1:

    输入: [3,2,3,null,3,null,1]
    
         3
        / 
       2   3
            
         3   1
    
    输出: 7 
    解释: 小偷一晚能够盗取的最高金额 = 3 + 3 + 1 = 7.
    

    示例 2:

    输入: [3,4,5,1,3,null,1]
    
         3
        / 
       4   5
      /     
     1   3   1
    
    输出: 9
    解释: 小偷一晚能够盗取的最高金额 = 4 + 5 = 9.
    

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/house-robber-iii
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    解题思路

    一定要先读懂题目意思:不能抢任意两个连着的节点,或者说,对于一个节点,要么抢当前节点及其左右节点的子节点(孙子节点),要么不抢当前节点而抢其左右直接子节点;

    思路1-基于上面的题意,用dp+递归的方式解决;

    该思路是使用节点记录中间值:

    1. 空节点返回0值;
    2. 递归计算得到左右节点的各自最大值;
    3. 在往上一层节点时,计算取以下的最大值:
      • 抢当前节点极其左右节点的子节点的各自最大值之和(孙子节点);
      • 不抢当前节点只抢左右子节点的各自最大值之和(直接节点);

    思路2-与1相同,但使用数组来记录中间数据;

    数组索引0表示不抢当前节点时最大值,1表示抢当前节点时的最大值,其他流程思路与1无异;

    算法源码示例

    package leetcode;
    
    /**
     * @author ZhouJie
     * @date 2020年3月24日 下午9:07:56 
     * @Description: 337. 打家劫舍 III
     * 
     *
     */
    public class LeetCode_0337 {
    
    }
    
    // Definition for a binary tree node.
    class TreeNode_0337 {
    	int val;
    	TreeNode_0337 left;
    	TreeNode_0337 right;
    
    	TreeNode_0337(int x) {
    		val = x;
    	}
    }
    
    class Solution_0337 {
    	/**
    	 * @author: ZhouJie
    	 * @date: 2020年3月31日 下午1:48:54 
    	 * @param: @param root
    	 * @param: @return
    	 * @return: int
    	 * @Description: 1-对于一个节点来说,当前能偷到的最大值有两个可能:
    	 * 				- 偷当前节点以及其左右节点的子节点中的各自最大值之和(4个孙子节点各自的最大值之和);
    	 * 				- 不偷当前节点,偷左右子节点各自的最大值之和;
    	 * 				- 子节点及孙子节点是一个可递归解决的问题;
    	 *
    	 */
    	public int rob_1(TreeNode_0337 root) {
    		TreeNode_0337 left = new TreeNode_0337(0);
    		TreeNode_0337 right = new TreeNode_0337(0);
    		return robMax_1(root, left, right);
    	}
    
    	/**
    	 * @author: ZhouJie
    	 * @date: 2020年3月31日 下午1:56:46 
    	 * @param: @param root
    	 * @param: @param left
    	 * @param: @param right
    	 * @param: @return
    	 * @return: int
    	 * @Description: 1-dp+递归(节点记录值);
    	 *
    	 */
    	private int robMax_1(TreeNode_0337 root, TreeNode_0337 left, TreeNode_0337 right) {
    		if (root == null) {
    			return 0;
    		} else {
    			// 四个孙子节点
    			TreeNode_0337 ll, lr, rl, rr;
    			ll = new TreeNode_0337(0);
    			lr = new TreeNode_0337(0);
    			rl = new TreeNode_0337(0);
    			rr = new TreeNode_0337(0);
    			// 左右子节点的最大值
    			left.val = robMax_1(root.left, ll, lr);
    			right.val = robMax_1(root.right, rl, rr);
    			return Math.max(root.val + ll.val + lr.val + rl.val + rr.val, left.val + right.val);
    		}
    	}
    
    	/**
    	 * @author: ZhouJie
    	 * @date: 2020年3月31日 下午1:57:30 
    	 * @param: @param root
    	 * @param: @return
    	 * @return: int
    	 * @Description: 2-与1的区别仅在于使用数组保存中间值;
    	 *
    	 */
    	public int rob_2(TreeNode_0337 root) {
    		int[] rob = robMax_2(root);
    		return Math.max(rob[0], rob[1]);
    	}
    
    	private int[] robMax_2(TreeNode_0337 root) {
    		if (root == null) {
    			// 空节点返回空数组给上层计算用
    			return new int[2];
    		}
    		// 左右子节点最终rob数组
    		int[] left = robMax_2(root.left);
    		int[] right = robMax_2(root.right);
    		int[] robbing = new int[2];
    		// 最终做一次选择,不抢当前根节点(即左右子节点可抢可不抢),那么就从左右子节点中各选择抢与不抢的最大值即可;
    		robbing[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
    		// 若抢当前跟节点,则只能选择左右子节点不抢时的值并加上当前根节点的值
    		robbing[1] = left[0] + right[0] + root.val;
    		return robbing;
    	}
    }
    
    
  • 相关阅读:
    产品中常用理论
    Mac下配置环境变量
    Maven仓库
    深入理解Spring中的各种注解
    JAVA中简单字符串分割
    WARN: HHH000277: Could not bind factory to JNDI
    dos命令窗口下下java命令提示找不到或无法加载主类
    数组实用类:Arrays
    数组
    线程创建方式
  • 原文地址:https://www.cnblogs.com/izhoujie/p/12604936.html
Copyright © 2011-2022 走看看