1.判断完全二叉树
题目描述: 判断一颗树是不是完全二叉树
public static boolean isCompleteTree(TreeNode root){
//通过层序遍历的方式来实现
if(root==null){
return true;
}
//分成两个阶段来进行判断
//这个变量为false时,表示在第一阶段
//这个变量为true时,表示是在第一阶段
boolean isLevel2=false;
//层序遍历,需要有一个队列
Queue<TreeNode> queue=new LinkedList<>();
while (true) {
TreeNode cur=queue.poll();
if(cur==null){
break;
}
//争对当前结点进行访问
//此处的访问是一系列的逻辑判断
if(!isLevel2){
//第一阶段的逻辑
if(cur.left!=null&&cur.right!=null){
//这是一个符合要求的结点,继续往下遍历
//次数把左右子树直接入队列即可
queue.offer(root.left);
queue.offer(root.right);
}else if(cur.left==null&&cur.right!=null){
//第一阶段中发现只有只有右子树的结点
//说明这个树一定不是完全二叉树
return false;
}else if(cur.left!=null&&cur.right==null){
isLevel2=true;
queue.offer(cur.left);
}else{
//这个结点没有子树,也是进入到第二阶段
isLevel2=true;
}
}else{
//第二阶段的逻辑
if(cur.left!=null||cur.right!=null){
//发现第二阶段的某个结点的子树不为空,此时就认为当前的结点不是完全二叉树
return false;
}
}
}
//遍历了整个树,没有发现return false的反例
return true;
}
2.二叉树的遍历
题目描述: 编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。
import java.util.Scanner;
public class Main {
public static class TreeNode{
public char val;
public TreeNode left;
public TreeNode right;
public TreeNode(char val){
this.val=val;
}
}
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
//注意
//系统给的系统用例往往是多种
while(scanner.hasNext()){
String line=scanner.next();
TreeNode root=build(line);
inOrder(root);
//打印换行
System.out.println();
}
}
//当前的String line里面的每个字符都堆到一个结点的字符
//接下来我们要进行递归
//为了在递归过程中,也能明确的知道进行到那个字符,然后使用index
public static int index=0;
public static TreeNode build(String line){
//由于用例可能有多组,所以把index设置为0
index=0;
return _build(line);
}
//实际上是通过这个_build方法来进行递归的
//不能直接拿build来进行递归,因为build里面有index=0,
// 如果直接那build方法就会直接弄混
public static TreeNode _build(String line){
//首先先根据index把当前要处理的结点获取到
char ch=line.charAt(index);
if(ch=='#'){
//遇到#说明当前结点是孔数,返回空树
return null;
}
TreeNode root=new TreeNode(ch);
index++;
root.left=_build(line);
index++;
root.right=_build(line);
return root;
}
public static void inOrder(TreeNode root){
if(root==null){
return;
}
inOrder(root.left);
System.out.print(root.val+" ");
inOrder(root.right);
}
}
3.二叉树的层序遍历
题目描述: 给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
//result表示最终的结果
//为了能够在递归方法中方便的进行更新,把这个结果做成了一个成员变量
public List<List<Integer>> result=null;
public List<List<Integer>> levelOrder(TreeNode root) {
//保证我们每次调用levelOrder都有新的result,
// 防止多个用例之间相互干扰。
result =new ArrayList<>();
if(root==null){
return result;
}
//借助一个辅助的方法,对该树进行递归的先序遍历
//在递归的参数上,加上层数信息
helper(root,0);
return result;
}
public void helper(TreeNode root,int level){
if(level==result.size()){
//如果满足这个条件,意味着下面直接取会下标越界
//越界的情况,就需要给二维List添加新行
result.add(new ArrayList<Integer>());
}
//就是一个简单的先序遍历
//访问结点操作就是把当前结点放到result的合适位置上
result.get(level).add(root.val);
//递归左右子树即可
if(root.left!=null){
helper(root.left,level+1);
}
if(root.right!=null){
helper(root.right,level+1);
}
}
}
4.求最小公共祖先
题目描述: 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lca=null;
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null){
return null;
}
//我们期望在find在递归的过程中,找到lca
find(root,p,q);
return lca;
}
//只要当前的root能找到就返回true,找到一个就返回
public boolean find(TreeNode root,TreeNode p,TreeNode q){
//find方法要做的事情,是争对当前结点查找p和q
if(root==null){
//空树里肯定找不到,然后返回false
return false;
}
int mid=(root == p || root == q) ? 1 : 0;
int left=find(root.left,p,q)?1:0;
int right=find(root.right,p,q)?1:0;
if(mid+left+right==2){
//p和q来自于三个渠道中来两个,就认为找到了
lca=root;
}
//只要找到了p或者的一个就可以了
return (left+right+mid)>0;
}
}
5.二叉搜索树与双向链表
题目描述: 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree == null){
//空树,就直接返回空链表
return null;
}
if (pRootOfTree.left == null && pRootOfTree.right == null){
//只有一个根节点的树,直接返回该节点
return pRootOfTree;
}
//递归处理左子树,得到左子树的链表的头节点
TreeNode leftHead=Convert(pRootOfTree.left);
//把当前结点尾插到左侧链表的末尾
//需要先找到左侧的链表的末尾操作
TreeNode leftTail=leftHead;
while(leftTail!=null&&leftTail!=null&&leftTail.right!=null){
leftTail=leftTail.right;
}
//进行尾插操作
if(leftHead!=null){
//如果根节点的左子树是null
//就不能进行下列代码中了
leftTail.right=pRootOfTree;
pRootOfTree.left=leftTail;
}
//递归处理右子树
TreeNode rightHead=Convert(pRootOfTree.right);
//把当前结点插入到右侧链表的头部
if(rightHead!=null){
rightHead.left=pRootOfTree;
pRootOfTree.right=rightHead;
}
//最终返回当前这个组装好这个链表的头节点
return leftHead!=null?leftHead:pRootOfTree;
}
}
6.先序中序构建二叉树
题目描述: 根据一棵树的前序遍历与中序遍历构造二叉树。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int index=0;
public TreeNode buildTree(int[] preorder, int[] inorder) {
//为了让我们多个用例之间相互不影响,都要把index清空
index = 0;
//当前给定的第二个遍历结果,int []
//为了让后面的操作方便,需要把int [] =List<Integer>
//方便后续代码中截取中序中的一部分
List<Integer> inorderList=new ArrayList<>();
for(int x:inorder){
inorderList.add(x);
}
return _buildTree(preorder,inorderList);
}
//第一个参数表示整个大的二叉树的先序结果,不管怎样,他的值都不会变化
//第二个参数表示当前那对应的子树的中序
//会随着递归的进行,会发现变话
public TreeNode _buildTree(int [] preorder, List<Integer> inorder ){
if(inorder.isEmpty()){
return null;
}
if(index >= preorder.length){
//遍历结束,已经把先序结果都访问完了
//这个条件理论上是执行不到的
return null;
}
//接下来创建当前节点
TreeNode root=new TreeNode(preorder[index]);
index++;//构建好一个结点之后++,已被下次构建节点的时候,得到下次的元素
//要去进行递归了
//要把左右子树的中序结果告诉递归方法了
//左右子树的中序结果就包含在了当前的中序结果之中
//中序结果=左子树的中序结果+右子树的中序结果
//只要知道了根节点,就可以知道了左右子树的根节点
int pos = inorder.indexOf(root.val);
//左子树的中序结果[0,pos)
root.left=_buildTree(preorder,inorder.subList(0,pos));
//右子树的中序结果为[pos+1,len)
root.right=_buildTree(preorder,inorder.subList(pos+1,inorder.size()));
return root;
}
}