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);
}
}
}