二叉树的进阶训练

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

}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值