package com.wschase.binarytree;
import java.util.*;
/**二叉树的进阶面试题
* Author:WSChase
* Created:2019/4/10
*/
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
public class Solution {
/**
* 1.二叉树的前序遍历——非递归实现
*/
// public List<Integer> preorderTraversal(TreeNode root) {
// //二叉树的前序遍历的非递归实现:
// //我们用一个栈来存放我们遍历的结点,然后通过查看访问结点的次数就可以知道前序遍历的结果
// Stack<TreeNode> s=new Stack<>();
// List<Integer> list=new ArrayList<>();
// //我们进行遍历时的当前结点
// TreeNode cur=root;
// //当前栈顶的结点
// TreeNode top=null;
//
// while(cur!=null||!s.empty()){
// //实现一路向左把结点放进栈里面
// while(cur!=null){
// list.add(cur.val);
// s.push(cur);
// cur=cur.left;
// }
// top=s.peek();
// s.pop();
// cur=top.right;
// }
// return list;
// }
/**
* 2.二叉树的中序遍历——非递归实现
*/
// public List<Integer> inorderTraversal(TreeNode root) {
// //二叉树的前序遍历的非递归实现:
// //我们用一个栈来存放我们遍历的结点,然后通过查看访问结点的次数就可以知道前序遍历的结果
// Stack<TreeNode> s=new Stack<>();
// List<Integer> list=new ArrayList<>();
// //我们进行遍历时的当前结点
// TreeNode cur=root;
// //当前栈顶的结点
// TreeNode top=null;
//
// while(cur!=null||!s.empty()){
// //实现一路向左把结点放进栈里面
// while(cur!=null){
// s.push(cur);
// cur=cur.left;
// }
//
// //这个地方表示第二次遇到这个结点
// top=s.peek();
// list.add(top.val);
// s.pop();
// cur=top.right;
// }
// return list;
// }
/**
* 3.二叉树的后序遍历——非递归实现
*/
// public List<Integer> postorderTraversal(TreeNode root) {
// Stack<TreeNode> s=new Stack<>();
// List<Integer> list=new ArrayList<>();
// TreeNode cur=root;
// TreeNode top=null;
// TreeNode last=null;
// while(cur!=null||!s.empty()){
// //第一次遇到这个结点
// while (cur!=null){
// //一路向左的过程
// s.push(cur);
// cur=cur.left;
// }
// //一定是向左遇到null以后,利用栈处理剩余的右子树
// top=s.peek();
// if(top.right==null){
// list.add(top.val);
// s.pop();
// //上一个被遍历过三次的结点
// last=top;
// }else {
// cur=top.right;
// }
// }
// return list;
// }
/**
* 4.
*/
/**
*5.二叉树的层序遍历
*/
// public List<List<Integer>> levelOrder(TreeNode root) {
// //这个层序遍历返回的结果是一个List集合,但是这个结合比较特殊,因为最后需要的是一个二维数组
// //就是在List集合里面存放的还是List集合。
//
// //(1)根节点为空
// if(root==null){
// //返回一个空的顺序表
// return new ArrayList<>();
// }
//
// //我们需要一个队列来实现中间的转化关系:就是将一颗二叉树首先放进一个队列里面,然后取出来放进集合里面
// Queue<TreeNode> queue=new LinkedList<>();
//
// //再定义一个集合来存放返回的结果
// List<List<Integer>> result=new ArrayList<>();
//
// //根节点不为空的情况
// queue.add(root);
//
//
// while (!queue.isEmpty()){
// //用于计数队列里面还有几个数
// int count= queue.size();
// List<Integer> list=new ArrayList<>();
// while (count>0){
//
// //(1)将根节点放进集合里面了
// TreeNode top=queue.peek();
// queue.poll();
// list.add(top.val);
//
// //再判断它的左子树
// if(top.left!=null){
// queue.add(top.left);
// }
//
// //再判断右子树
// if(top.right!=null){
// queue.add(top.right);
// }
// count--;
// }
//
// //如果跳出了上面的循环以后就结束了遍历整个二叉树,此时将这个集合放进一个集合里面
// //这个result就是一个二位的数组——二维顺序表
// result.add(list);
// }
// return result;
// }
/**
* 6.给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
*
* 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
*
* 例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]
* 示例 1:
*
* 输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
* 输出: 3
* 解释: 节点 5 和节点 1 的最近公共祖先是节点 3。
*/
/**
判断最近公共祖先结点的思路:
我们首先这两个结点是否在同一棵树上面,如果不在那么它们的最近祖先结点就是根节点;
如果同时在左子树,那么再去左子树判断,直到根节点为null的时候才终止判断;
如果同时在右子树,那么就去右子树判断,这个过程就是递归的过程。
*/
// public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
// if(root==null){
// return root;
// }
// if(p==root||q==root){
// return root;
// }
// TreeNode left=lowestCommonAncestor(root.left,p,q);
// TreeNode right=lowestCommonAncestor(root.right,p,q);
//
// //这个表示这两个结点一个在根节点的左子树、一个在根节点的右子树——最近公共祖先结点就是根节点
// if(left!=null&&right!=null){
// return root;
// }
// if(left!=null){
// return left;
// }
// if(right!=null){
// return right;
// }
// return null;
// }
/**
* 7.输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。
* 要求不能创建任何新的结点,只能调整树中结点指针的指向。
*/
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
/**
* 在根节点(当前值)的前面访问的是左子树,那么一个结点的左子树就是它的前驱结点;
* 一个结点的右子树是在它访问之后访问的,所以它的右孩子作为它的后继,这样就构成了
* 双向链表。由于中序遍历的顺序本来就是:左子树——根节点——右子树,所以我们只需要修改左子树就可以
* 实现双向链表。
* @param root
* @return
*/
// public TreeNode Convert(TreeNode root) {
// if (root == null)
// return null;
// Stack<TreeNode> stack = new Stack<>();
// TreeNode p = root;
// TreeNode pre = null;// 用于保存中序遍历序列的上的节点
// //是否是第一次遍历这个结点
// boolean isFirst = true;
// while (p != null || !stack.isEmpty()) {
// while (p != null) {
// stack.push(p);
// p = p.left;
// }
// p = stack.pop();
// if (isFirst) {
// //在中序遍历中的第一次遍历的结点为双向链表的前驱
// root = p;// 将中序遍历序列中的第一个节点记为root
// pre = root;
// isFirst = false;
// } else {
// //这个地方表示第二次遇到这个结点
// pre.right = p;//这个pre.right就相当于是pre.next
// p.left = pre;
// pre = p;
// }
// p = p.right;
// }
//
// //通过root可以找到这个链表
// return root;
// }
/**
* 8.根据一棵树的前序遍历与中序遍历构造二叉树。
* 注意:
* 你可以假设树中没有重复的元素。
* 例如,给出
* 前序遍历 preorder = [3,9,20,15,7]
* 中序遍历 inorder = [9,3,15,20,7]
* 返回如下的二叉树:
* 3
* / \
* 9 20
* / \
* 15 7
*/
// public TreeNode build(int[] preorder,int[] inorder,int startPre,int endPre,int startIn,int endIn){
// if(startPre>endPre){
// return null;
// }
// if(startPre==endPre){
// return new TreeNode(preorder[startPre]);
// }
// int rootval=preorder[startPre];
// TreeNode root=new TreeNode(rootval);
// //在中序遍历里面找到属于二叉树的左子树和右子树的结点
// for(int i=startIn;i<=endIn;i++){
// if(inorder[i]==rootval){
// root.left=build(preorder,inorder,startPre+1,startPre+i-startIn,startIn,i-1);
// root.right=build(preorder,inorder,startPre+i-startIn+1,endPre,i+1,endIn);
// break;
// }
// }
// return root;
// }
// public TreeNode buildTree(int[] preorder, int[] inorder) {
//
// return build(preorder, inorder, 0, preorder.length - 1, 0, inorder.length - 1);
//
// }
/**
* 9.根据一棵树的中序遍历与后序遍历构造二叉树。
* 注意:
* 你可以假设树中没有重复的元素。
* 例如,给出
* 中序遍历 inorder = [9,3,15,20,7]
* 后序遍历 postorder = [9,15,7,20,3]
* 返回如下的二叉树:
*
* 3
* / \
* 9 20
* / \
* 15 7
*/
// public TreeNode buildTree(int[] inorder, int[] postorder) {
// return realTree(inorder,0,inorder.length,postorder,0,postorder.length);
// }
//
// public TreeNode realTree(int[] inorder,int a,int b,int[] postorder,int c,int d){
// if(a==b || c==d)
// return null;
// TreeNode node=new TreeNode(postorder[d-1]);
// for(int i=a;i<b;i++){
// if(inorder[i]==postorder[d-1]){
// node.left=realTree(inorder,a,i,postorder,c,i+c-a);
// node.right=realTree(inorder,i+1,b,postorder,i+c-a,d-1);
// break;
// }
// }
// return node;
// }
}