package com.wschase.binarytree;
import java.util.*;
/**二叉树的基础面试题
* Author:WSChase
* Created:2019/4/7
*/
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
public class Solution {
/**
* 1.升级版的二叉树前序链表
*给定一个二叉树,返回它的 前序 遍历。
* 示例:
* 输入: [1,null,2,3]
* 1
* \
* 2
* /
* 3
*
* 输出: [1,2,3]
*/
/**
* Definition for a binary tree node.
*/
// public List<Integer> preorderTraversal(TreeNode root) {
// //这个前序遍历和我们之前些的简单前序遍历的区别就是需要将遍历的结果放进一个顺序表(数组)里面,
// //并且返回这个数组(我们只需要返回数组名就可以了)。
//
// //我们先开辟一个动态的数组(就是java中的ArrayList链表),这个数组用来存放遍历以后的结点
// List<Integer> arrayList=new ArrayList<>();
//
// _preorder(root,arrayList);
// return arrayList;
//
// }
// public void _preorder(TreeNode root,List<Integer> list){
//
// //首先是递归终止条件
// if(root==null){
// return ;
// }else{
// //根节点——>左子树——>右子树
// //根节点就是我们前序遍历真正意义上的输出结点
// list.add(root.val);
//
// //然后是递归左子树
// _preorder(root.left,list);
//
// //然后是递归右子树
// _preorder(root.right,list);
// }
// }
/**
* 2.给定一个二叉树,返回它的中序遍历。
* 示例:
* 输入: [1,null,2,3]
* 1
* \
* 2
* /
* 3
*
* 输出: [1,3,2]
* @param root
* @return
*/
// public List<Integer> inorderTraversal(TreeNode root) {
// //这个前序遍历和我们之前些的简单前序遍历的区别就是需要将遍历的结果放进一个顺序表(数组)里面,
// //并且返回这个数组(我们只需要返回数组名就可以了)。
//
// //我们先开辟一个动态的数组(就是java中的ArrayList链表),这个数组用来存放遍历以后的结点
// List<Integer> arrayList=new ArrayList<>();
//
// _inorder(root,arrayList);
// return arrayList;
//
// }
// public void _inorder(TreeNode root,List<Integer> list){
//
// //首先是递归终止条件
// if(root==null){
// return ;
// }else{
// //左子树——>根节点——>右子树
//
// //首先是递归左子树
// _inorder(root.left,list);
//
// //然后根节点就是我们前序遍历真正意义上的输出结点
// list.add(root.val);
// //最后是递归右子树
// _inorder(root.right,list);
// }
// }
/**
* 3.给定一个二叉树,返回它的 后序 遍历。
* 示例:
* 输入: [1,null,2,3]
* 1
* \
* 2
* /
* 3
*
* 输出: [3,2,1]
*/
// public List<Integer> postorderTraversal(TreeNode root) {
// //这个前序遍历和我们之前些的简单前序遍历的区别就是需要将遍历的结果放进一个顺序表(数组)里面,
// //并且返回这个数组(我们只需要返回数组名就可以了)。
//
// //我们先开辟一个动态的数组(就是java中的ArrayList链表),这个数组用来存放遍历以后的结点
// List<Integer> arrayList=new ArrayList<>();
//
// _postorder(root,arrayList);
// return arrayList;
// }
//
// public void _postorder(TreeNode root,List<Integer> list){
//
// //首先是递归终止条件
// if(root==null){
// return ;
// }else{
// //左子树——>右子树——>根节点
//
// //首先是递归左子树
// _postorder(root.left,list);
//
// //然后是递归右子树
// _postorder(root.right,list);
//
// //最后根节点就是我们前序遍历真正意义上的输出结点
// list.add(root.val);
// }
// }
/**
* 4.给定两个二叉树,编写一个函数来检验它们是否相同。
*
* 如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
*
* 示例 1:
* 输入: 1 1
* / \ / \
* 2 3 2 3
* [1,2,3], [1,2,3]
* 输出: true
*/
/**
分析:我们分析题意可以知道,比较两颗二叉树是否相等总共分为三种情况:
两个都为空树发的时候必然是相等的;
一个为空树一个不为空树是不相等的;
两个都不为空树则分别进行比较两个的左子树和右子树;
*/
// public boolean isSameTree(TreeNode p, TreeNode q) {
// if(p==null && q==null){
// return true;
// }
// if(p!=null && q==null){
// return false;
// }
// if(p==null && q!=null){
// return false;
// }
//
// //下面用的相当于是前序遍历:根节点就是相等就直接输出了——左子树——右子树
//
// //如果这个地方写相等那么会出现一个问题就是在两棵树里面只要遇到了相同的结点就会返回true
// //所以这个地方我们需要判断不相等。
// if(p.val!=q.val){
//
// return false;
// }
// if(isSameTree(p.left,q.left)==false){
// return false;
// }
// if(isSameTree(p.right,q.right)==false){
// return false;
// }
// //如果上面的都不满足,那就是经过比较所有的结点都是相等的,返回true
// return true;
// }
/**
*5.给定一个二叉树,检查它是否是镜像对称的。
*
* 例如,二叉树 [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
*/
/**
* 分析:
*对称二叉树:我们最重要的就是要将它分开成两棵树进行判断,对于根节点我们单独考虑。
如果一棵树只有一个根节点,那么这棵树一定是二叉树。否则我们将这棵树的左右子树进行镜像比较;
*/
/*
我们首先编写一个函数来实现镜像比较
*/
// public boolean isMirrorTree(TreeNode p,TreeNode q){
// if(p==null&&q==null){
// return true;
// }
// //这个地方必须包含所有为空的情况,不然下面的引用就会出现空指针异常
// //这两种写法是等价的:if((p!=null&&q==null)||(p==null&&q!=null))<==>(p==null||q==null)
// if((p!=null&&q==null)||(p==null&&q!=null)){
// return false;
// }
// return (p.val==q.val&&
// isMirrorTree(p.left,q.right)&&
// isMirrorTree(p.right,q.left));
// }
// public boolean isSymmetric(TreeNode root) {
// //下面其实就是使用前序遍历实现对称二叉树的判断
// if(root==null){
// return true;
// }
// //对于对称二叉树我们的终止条件需要对一个结点单独考虑,一个结点的就是对称二叉树
// if(root!=null&&root.left==null&&root.right==null){
// return true;
// }
//
// return isMirrorTree(root.left,root.right);
// }
/**
* 6.给定一个二叉树,找出其最大深度。
*
* 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
*
* 说明: 叶子节点是指没有子节点的节点。
*
* 示例:
* 给定二叉树 [3,9,20,null,null,15,7],
*
* 3
* / \
* 9 20
* / \
* 15 7
*/
// public int maxDepth(TreeNode root) {
// if(root==null){
// return 0;
// }
// int leftMax=maxDepth(root.left);
// int rightMax=maxDepth(root.right);
// return leftMax>rightMax?leftMax+1:rightMax+1;
// }
/**
* 7.给定一个二叉树,判断它是否是高度平衡的二叉树。
*
* 本题中,一棵高度平衡二叉树定义为:
*
* 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
*
* 示例 1:
*
* 给定二叉树 [3,9,20,null,null,15,7]
*
* 3
* / \
* 9 20
* / \
* 15 7
*/
/**
我们首先需要定义一个方法实现求解二叉树的高度
*/
// public int maxDepth(TreeNode root) {
// if(root==null){
// return 0;
// }
// int leftMax=maxDepth(root.left);
// int rightMax=maxDepth(root.right);
// return leftMax>rightMax?leftMax+1:rightMax+1;
// }
public int getHight(TreeNode root){
if(root==null){
return 0;
}
int leftHight=getHight(root.left);
int rightHight=getHight(root.right);
//
return leftHight>rightHight?leftHight+1:rightHiht+1;
}
//
// public boolean isBalanced(TreeNode root) {
// if(root==null){
// return true;
// }
// //如果左子树不为平衡二叉树则整棵树一定不是平衡二叉树
// boolean leftBanlance=isBalanced(root.left);
// if(!leftBanlance){
// return false;
// }
//
// //如果右子树不是平衡二叉树那么这棵树也一定不是平衡二叉树
// boolean rightBanlance=isBalanced(root.right);
// if(!rightBanlance){
// return false;
// }
// int leftHight=maxDepth(root.left);
// int rightHight=maxDepth(root.right);
// int abslute=leftHight-rightHight;
// // if(abslute<0){
// // abslute=abslute*(-1);
// // }
// if(abslute>=-1&&abslute<=1){
// return true;
// }
// else{
// return false;
// }
// }
/**
* 8.另一棵树的子树
* 给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。
* 示例 1:
* 给定的树 s:
* 3
* / \
* 4 5
* / \
* 1 2
* 给定的树 t:
* 4
* / \
* 1 2
*/
// //对于一棵树是否是另外一棵树的子树我们必须知道的是每个结点的值相同,并且树的结构也要是相同的
// public boolean isSameTree(TreeNode a,TreeNode t){
// if(a==null&&t==null){
// return true;
// }
// if(a==null||t==null){
// return false;
// }
// if(a.val!=t.val){
// return false;
// }
// if(isSameTree(a.left,t.left)==false){
// return false;
// }
// if(isSameTree(a.right,t.right)==false){
// return false;
// }
// return true;
// }
// public boolean isSubtree(TreeNode s, TreeNode t) {
// if(s==null){
// return false;
// }
// //下面的条件判断的次序是按照前序遍历来说实现的
//
// //(1)首先传入根节点进行判断是否为相同的二叉树
// if(isSameTree(s,t)){
// return true;
// }
//
// //(2)如果(1)没有通过说明以s的根节点的这棵树和t是不相等的,接下来判断
// //s的左孩子为跟结点的这棵树是否和t相等,如果不相等则继续按照这样的思想进行判断
// if(isSubtree(s.left,t)){
// return true;
// }
// if(isSubtree(s.right,t)){
// return true;
// }
// return false;
// }
/**
* 9.
*/
/**
首先定义一个结点的类
*/
/**
* (1)
*/
// class Node{
// char val;
// Node left;
// Node right;
// }
//
// /**
// 然后定义一个结果的类
// */
// class Result{
// //包含创建好的树的根节点
// Node node;
// //创建过程中用掉val的个数
// int used;
// }
// public class Main{
// //重建二叉树的方法:需要输入两个参数,一个是前序遍历二叉树的一个数组,一个是数组里面有效元素的个数
// public Result createTree(char[] preorder,int size){
// //终止条件:
// //一开始这个前序遍历的数组里面就没有元素
// if(size<=0){
// Result result=new Result();
// result.node=null;
// result.used=0;
// return result;
// }
//
// //一开始这个前序遍历的数组里面放的就是空
// if(preorder[0]=='#'){
// Result result=new Result();
// result.node=null;
// result.used=1;
// }
//
// //创建根节点:preorder[0]是根节点的值
// Node root=new Node();
// root.val=preorder[0];
// //创建左子树
// Result left=createTree(preorder+1,size-1);
//
// //创建右子树
// Result right=createTree(preorder+1+left.used,size-1-left.used);
//
// //将结点的之间的关系连接起来
// root.left=left.node;
// root.right=right.node;
//
// //创建一个返回结果的结点
// Result result=new Result();
// result.node=root;
// result.used=1+left.used+right.used;
// return result;
// }
//
// /**
// 中序遍历
// */
// public void inorder(Node root){
// if(root==null){
// return;
// }
//
// inorder(root.left);
// System.out.println(root.val);
// inorder(root.right);
// }
//
// public static void mian(String[] args){
// char[] preorder=new char[1000];
// Scanner scanner=new Scanner();
// preorder=System.in(scanner);
// int size=preorder.length;
// Result result=createTree(preorder,size);
// inorder(result);
// }
// }
/**
* (2)
*/
// public class Main{
// public static String str = "";
// public static void main(String[] args){
// Scanner scanner=new Scanner(System.in);
// String str=scanner.nextLine();
// while(str!=null){
// //采用链表来处理二叉树
// Queue<Character> queue = new LinkedList<Character>();
// for(int i=0;i<str.length();i++){
// queue.offer(str.charAt(i));
// }
//
// //返回这棵二叉树的根节点可以找到这棵二叉树了
// BinaryTree root=build(queue);
// midOrder(root);
// }
// reader.close();
// }
//
// //根据前序遍历重建二叉树
// public static BinaryTree build(Queue<Character> queue){
// char c = queue.poll();
// if(c=='#'){
// return null;
// }
// BinaryTree root = new BinaryTree();
// root.s = c;
// root.l_child = build(queue);
// root.r_child = build(queue);
// return root;
// }
// public static void midOrder(BinaryTree root){
// if(root.l_child!=null){
// midOrder(root.l_child);
// }
// System.out.print(root.s+" ");
// if(root.r_child!=null){
// midOrder(root.r_child);
// }
// }
// }
// class BinaryTree{
// public BinaryTree l_child;
// public BinaryTree r_child;
// public char s;
// public BinaryTree(){
//
// }
// public BinaryTree(BinaryTree l,BinaryTree r,char s){
// this.l_child = l;
// this.r_child = r;
// }
// }
/**
* 10.二叉树的层序遍历
* 给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。
* 例如:
* 给定二叉树: [3,9,20,null,null,15,7],
* 3
* / \
* 9 20
* / \
* 15 7
*/
// public List<List<Integer>> levelOrder(TreeNode root) {
// if(root==null){
// return new ArrayList<>();
// }
//
// //这个list顺序表存放的是要返回的结果
// List<List<Integer>> res=new ArrayList<>();
// //取个队列:存放Node对象
// Queue<TreeNode> q=new LinkedList<>();
// q.add(root);
// while(!q.isEmpty()){
// int count=q.size();
// List<Integer> list=new ArrayList<>();
// while(count>0){
// //首先是查看队首元素
// TreeNode node=q.poll();
// list.add(node.val);
// if(node.left!=null){
// q.add(node.left);
// }
// if(node.right!=null){
// q.add(node.right);
// }
// count--;
// }
// res.add(list);
// }
// return res;
// }
/**
* 11.求叶子结点的个数
*/
//方法1:遍历方法
// public int getLeafSize(TreeNode root){
// int count=0;
// if(root==null){
// return 0;
// }
// //叶子结点:就是这个结点没有左右结点
// if(root.left==null&&root.right==null){
// count++;
// }
// getLeafSize(root.left);
// getLeafSize(root.right);
// return count;
// }
//方法2:递推方法实现
// public int getLeafSize(TreeNode root){
// if(root==null){
// return 0;
// }
// if(root.left==null&&root.right==null){
// return 1;
// }
//
// //一棵树的叶子节点就是左右子树的叶子节点之和
// return getLeafSize(root.left)+getLeafSize(root.right);
//
// }
/**
* 12.求第k层上的结点个数
*/
//public int levelk(TreeNode root,int k){
// if(root==null){
// return 0;
// }
// if(root==null){
// return 1;
// }
// return levelk(root.left,k-1)+levelk(root.right,k-1);
//}
/**
* 13.在树中查找
*/
// public TreeNode find(TreeNode root,char val){
// //先判断根
// if(root.val==val){
// return root;
// }
// //如果根节点不是就去左子树找
// TreeNode rleft=find(root.left,val);
// if(rleft!=null){
// return rleft;
// }
//
// //再没有找到就去右子树找
// TreeNode rRight=find(root.right,val);
// if(rRight!=null){
// return rRight;
// }
// return null;
// }
/**
* 14.如何判断一个树是完全二叉树
*/
// public boolean isCompleteTree(TreeNode root){
// if(root==null){
// return true;
// }
// Queue<TreeNode> q=new LinkedList<>();
// ((LinkedList<TreeNode>) q).push(root);
// while (true){
// TreeNode node=((LinkedList<TreeNode>) q).getFirst();
// q.poll();
// if(node==null){
// //在层序遍历中遇到空结点
// break;
// }
// ((LinkedList<TreeNode>) q).push(node.left);
// ((LinkedList<TreeNode>) q).push(node.right);
// }
// //检查剩下的结点中有没有空结点
// while (!q.isEmpty()){
// Node node=((LinkedList<TreeNode>) q).getFirst();
// q.poll();
// if(node!=null){
// return false;
// }
// }
// return true;
// }
}
二叉树的基础面试题
最新推荐文章于 2020-01-09 22:02:35 发布