标签:流程 ISE turn 查看 代码 class 效率 原来 元素
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ 9 20
/ 15 7
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
前序遍历的性质:节点按照【根节点|左子树|右子树】排序
中序遍历的性质:节点按照【左子树|根节点|右子树】排序
以题目示例为例:
前序遍历划分 [ 3 | 9 | 20 15 7 ]
中序遍历划分 [ 9 | 3 | 15 20 7 ]
根据以上性质,可得出以下推论:
前序遍历的首元素 为 树的根节点 node 的值。
在中序遍历中搜索根节点 node 的索引 ,可将 中序遍历 划分为 [ 左子树 | 根节点 | 右子树 ] 。
根据中序遍历中的左 / 右子树的节点数量,可将 前序遍历 划分为 [ 根节点 | 左子树 | 右子树 ] 。
以上子树的递推性质是 分治算法 的体现,考虑通过递归对所有子树进行划分。
分治算法解析:
递推参数: 根节点在前序遍历的索引 root 、子树在中序遍历的左边界 left 、子树在中序遍历的右边界 right ;
终止条件: 当 left > right ,代表已经越过叶节点,此时返回 nullnull ;
递推工作:
建立根节点 node : 节点值为 preorder[root] ;
划分左右子树: 查找根节点在中序遍历 inorder 中的索引 i ;
为了提升效率,本文使用哈希表 dic 存储中序遍历的值与索引的映射,查找操作的时间复杂度为 O(1)O(1)
构建左右子树: 开启左右子树递归;
i - left + root + 1含义为 根节点索引 + 左子树长度 + 1
返回值: 回溯返回 node ,作为上一层递归中根节点的左 / 右子节点;
package com.leetcode.offer.tree;
import com.labuladong.preDefine.TreeNode;
import java.util.HashMap;
public class BuildTree {
HashMap<Integer, Integer> map = new HashMap<>();//标记中序遍历
int[] preorder;//保留的先序遍历,方便递归时依据索引查看先序遍历的值
public TreeNode buildTree(int[] preorder, int[] inorder) {
this.preorder = preorder;
//将中序遍历的值及索引放在map中,方便递归时获取左子树与右子树的数量及其根的索引
for (int i = 0; i < inorder.length; i++) {
map.put(inorder[i], i);
}
//三个索引分别为
//当前根的的索引
//递归树的左边界,即数组左边界
//递归树的右边界,即数组右边界
return recur(0,0,inorder.length-1);
}
TreeNode recur(int pre_root, int in_left, int in_right){
if(in_left > in_right) {
return null;// 相等的话就是自己
}
TreeNode root = new TreeNode(preorder[pre_root]);//获取root节点
int idx = map.get(preorder[pre_root]);//获取在中序遍历中根节点所在索引,以方便获取左子树的数量
//左子树的根的索引为先序中的根节点+1
//递归左子树的左边界为原来的中序in_left
//递归右子树的右边界为中序中的根节点索引-1
root.left = recur(pre_root+1, in_left, idx-1);
//右子树的根的索引为先序中的 当前根位置 + 左子树的数量 + 1
//递归右子树的左边界为中序中当前根节点+1
//递归右子树的有边界为中序中原来右子树的边界
root.right = recur(pre_root + (idx - in_left) + 1, idx+1, in_right);
return root;
}
}
ps:感觉这道题好难啊。
输入两棵二叉树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
根据性质来讲,若树B是树A的子结构,则子结构的根节点可能为树A的任意一个节点。因此判断树B是否是A的子结构需要完成以下两步工作:
recur(A, B) 函数:
isSubStructure(A, B) 函数:
以上
2.
3.
实质上是在对树 AA 做 先序遍历 。
class Solution {
public boolean isSubStructure(TreeNode A, TreeNode B) {
return (A != null && B != null) && (recur(A, B) || isSubStructure(A.left, B) || isSubStructure(A.right, B));
}
boolean recur(TreeNode A, TreeNode B) {
if(B == null) return true;
if(A == null || A.val != B.val) return false;
return recur(A.left, B.left) && recur(A.right, B.right);
}
}
请完成一个函数,输入一个二叉树,该函数输出它的镜像。
例如输入:
4
/ 2 7
/ \ / 1 3 6 9
镜像输出:
4
/ 7 2
/ \ / 9 6 3 1
示例 1:
输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]
二叉树镜像定义: 对于二叉树中任意节点 root,设其左 / 右子节点分别为 left, right ;则在二叉树的镜像中的对应 root 节点,其左 / 右子节点分别为 right, left 。
根据二叉树镜像的定义,考虑递归遍历dfs二叉树,交换每个节点的左右子节点,即可生成二叉树的镜像
递归解析
为什么要暂存root的左子节点?
在递归右子节点root.left = mirrorTree(root.right)执行完毕之后,root.left的值已经发生改变,此时递归左子节点会出现问题。
class Solution {
public TreeNode mirrorTree(TreeNode root) {
if(root == null) return null;
TreeNode tmp = root.left;
root.left = mirrorTree(root.right);
root.right = mirrorTree(tmp);
return root;
}
}
利用栈(或队列)遍历树的所有节点node ,并交换每个node 的左 / 右子节点。
算法流程:
package com.leetcode.offer.tree;
import com.labuladong.preDefine.TreeNode;
import java.util.Stack;
public class MirrorTree_2 {
public TreeNode mirrorTree(TreeNode root) {
if(root==null){
return null;
}
Stack<TreeNode> stack = new Stack<>();
//首先加入根节点
stack.push(root);
// 循环交换
while (!stack.isEmpty()){
TreeNode node = stack.pop();
//添加子节点,将node左右子节点加入栈中
if(node.left!=null){
stack.push(node.left);
}
if(node.right!=null){
stack.push(node.right);
}
//交换节点
TreeNode temp = node.left;
node.left=node.right;
node.right = temp;
}
return root;
}
public static void main(String[] args) {
TreeNode a = new TreeNode(4);
TreeNode al = new TreeNode(2);
TreeNode ar = new TreeNode(7);
TreeNode all = new TreeNode(1);
TreeNode alr = new TreeNode(3);
TreeNode arl = new TreeNode(6);
TreeNode arr = new TreeNode(9);
a.left= al;
a.right=ar;
al.left=all;
al.right=alr;
ar.left= arl;
ar.right=arr;
System.out.println(new MirrorTree_2().mirrorTree(a));
}
}
请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
1
/ 2 2
/ \ / 3 4 4 3
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
1
/ 2 2
\ 3 3
示例 1:
输入:root = [1,2,2,3,4,4,3]
输出:true
示例 2:
输入:root = [1,2,2,null,3,null,3]
输出:false
对称二叉树定义: 对于树中 任意两个对称节点 L 和 R,一定有:
根据以上规律,考虑从顶至底递归,判断每对节点是否对称,从而判断树是否为对称二叉树。
算法流程:
isSymmetric(root) :
recur(L, R)
:
终止条件:
递推工作:
返回值: 两对节点都对称时,才是对称树,因此用与逻辑符 && 连接。
package com.leetcode.offer.tree;
import com.labuladong.preDefine.TreeNode;
public class IsSymmetric {
public boolean isSymmetric(TreeNode root) {
if(root==null){
return true;
}
return recur(root.left, root.right);
}
private boolean recur(TreeNode left, TreeNode right) {
if(left==null &&right==null){
return true;
}
if(left==null || right ==null|| left.val!=right.val){
return false;
}
return recur(left.left, right.right) && recur(left.right, right.left);
}
}
剑指 Offer 27. 二叉树的镜像(递归 / 辅助栈,清晰图解)
标签:流程 ISE turn 查看 代码 class 效率 原来 元素
原文地址:https://www.cnblogs.com/chenyameng/p/14988166.html