LeetCode170--重建二叉树(O07)、剪绳子I(O14-I)、树的子结构(O26)

1、重建二叉树

//输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。
//
// 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
//
//
//
// 示例 1:
//
//
//Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
//Output: [3,9,20,null,null,15,7]
//
//
// 示例 2:
//
//
//Input: preorder = [-1], inorder = [-1]
//Output: [-1]
//
//
//
//
// 限制:
//
// 0 <= 节点个数 <= 5000
//
//
//
// 注意:本题与主站 105 题重复:https://leetcode-cn.com/problems/construct-binary-tree-from-
//preorder-and-inorder-traversal/
// Related Topics 树 数组 哈希表 分治 二叉树

重建二叉树我们需要知道前序遍历的规则,它是先遍历根节点,再遍历左子树,最后遍历右子树,所以我们只需要每次抓住根节点或者左子树的根节点、右子树的根节点,并找到它们在中序遍历中的位置,就得知了其左、右节点,然后再将其当做根节点继续进行推导。注意:如何判断一个数组是否直接判断完,就直接需要保证传入函数的int_left < int_right

class Solution {
	int[] preorder;
	int[] inorder;
	int pre_index = 0;
	Map map = new HashMap<Integer, Integer>();
    public TreeNode buildTree(int[] preorder, int[] inorder) {
		this.preorder = preorder;
		this.inorder = inorder;
		int index = 0;
		for (Integer item : inorder) {
			map.put(item, index++);
		}
		//之所以加上左右边界是为了控制将数组给遍历完
		TreeNode root = helper(0, inorder.length-1);
		return root;
	}
	private TreeNode helper(int int_left, int int_right){
    	if(int_left > int_right){
    		return null;
		}
    	//前序遍历的当前节点作为根节点
		int num = preorder[pre_index++];
		TreeNode root = new TreeNode(num);
		int index = (int) map.get(num);
		//一直会遍历到左子树的最左节点
		root.left = helper(int_left, index-1);
		root.right = helper(index+1, int_right);
		return root;
	}
}

2、剪绳子I

//给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m - 1]
// 。请问 k[0]k[1]…*k[m - 1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘
//积是18。
//
// 答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
//
//
//
// 示例 1:
//
// 输入: 2
//输出: 1
//解释: 2 = 1 + 1, 1 × 1 = 1
//
// 示例 2:
//
// 输入: 10
//输出: 36
//解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
//
//
//
// 提示:
//
//
// 2 <= n <= 1000
//
//
// 注意:本题与主站 343 题相同:https://leetcode-cn.com/problems/integer-break/
// Related Topics 数学 动态规划

维护一个数组dp[i]表示长度为i的绳子的子段的最大乘积是多少。如果就切一刀,那么乘积就是j*(i-j),如果切几刀就是jdp[i-j],所以取最大值,最后的状态转移方程为:
dp[i] = max(j
(i-j),j*dp[i-j])

public int cuttingRope(int n) {
            //维护一个数组dp[i],求大小为i的数分为几段相乘的最大乘积
            int[] dp = new int[n+1];
            dp[2] = 1;
            for (int i = 3; i <= n ; i++) {
                //只减掉长度1,对最后的乘积没有任何增益
                for (int j = 2; j < i; j++) {
                    //这里分为剪成剪一次和剪多次
                    dp[i] = Math.max(dp[i], Math.max(j * (i - j), j * dp[i - j]));
                }
            }
            return dp[n];
        }

3、树的子结构

//输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
//
// B是A的子结构, 即 A中有出现和B相同的结构和节点值。
//
// 例如:
//给定的树 A:
//
// 3
// / \
// 4 5
// / \
// 1 2
//给定的树 B:
//
// 4
// /
// 1
//返回 true,因为 B 与 A 的一个子树拥有相同的结构和节点值。
//
// 示例 1:
//
// 输入:A = [1,2,3], B = [3,1]
//输出:false
//
//
// 示例 2:
//
// 输入:A = [3,4,5,1,2], B = [4,1]
//输出:true
//
// 限制:
//
// 0 <= 节点个数 <= 10000
// Related Topics 树 深度优先搜索 二叉树

利用递归,需要考虑这个B树是不是当前根节点的子结构,是不是A树左子树的子结构(由于我们进行了递归,这个就能直接判断更深的节点),是不是A树右子树的子结构。判断是不是子结构也采用递归。假如已经遍历完B了,不管A当前节点是什么都是子结构;加入遍历完了A,B没有遍历完或者当前两个节点不相等,那么也不是其子结构,最后我们利用继续递归的方式进行推导:

class Solution {
    public boolean isSubStructure(TreeNode A, TreeNode B) {
		if(A == null || B == null){
			return false;
		//需要考虑这个B树是不是当前根节点的子结构,是不是A树左子树的子结构(由于我们进行了递归,这个
		// 就能直接判断更深的节点),是不是A树右子树的子结构
		}else if(recur(A, B) || isSubStructure(A.left, B) || isSubStructure(A.right, B)){
			return true;
		}
		return false;
    }
    private boolean recur(TreeNode A, TreeNode B){
    	if(B == null){
    		return true;
		}else if(A == null || A.val != B.val){
    		return false;
		}else{
    		return recur(A.left, B.left) && recur(A.right, B.right);
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值