二叉树相关习题

1.判断两棵树是否相同

思路:可以采用递归的方法,首先判断根节点的值是否相同,若不相同则两个二叉树一定不同,若相同,再分别递归判断两个二叉树的左树以及右树是否相同。

代码:

public boolean isSameTree(TreeNode p, TreeNode q) {
        if(p==null&&q==null){
            return true;
        }
        if(p!=null&&q==null||p==null&&q!=null){
            return false;
        }
       //p!=null&&q!=null
        if(p.val!=q.val){
            return false;
        }
        return isSameTree(p.left,q.left)&&isSameTree(p.right,q.right);
    }

2.判断一棵树是不是另一棵树的子树

思路:同样采用递归的思路,可以先判断两棵树是不是同一颗数,如果是,则返回true,如果不是,可递归判断其左树、右树是否与该子树是同一棵树。

 public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        if(root==null||subRoot==null){
            return false;
        }
        if(isSameTree(root,subRoot)){
            return true;
        }
        return isSubtree(root.left,subRoot)||isSubtree(root.right,subRoot);
}

 3.求二叉树最大深度

思路:其实就是求树的高度,数的高度可以看做是左树或右树的最大值加1,通过递归即可实现

    int getHeight(TreeNode root){
        if(root==null){
            return 0;
        }
        int leftH=getHeight(root.left);
        int leftR=getHeight(root.right);
        return leftH-leftR>0?leftH+1:leftR+1;
    }

4.判断一颗树是否是平衡二叉树

思路:平衡二叉树是指每颗子树左右高度差不能超过1,并且其子树也应为平衡二叉树

    方法1
   //判断一棵树是不是平衡二叉树,时间复杂度为O(N^2)
    public boolean isBalanced(TreeNode root) {
        if(root==null){
            return true;
        }
        //getHeight在上面写过了
        int leftH=getHeight(root.left);
        int leftR=getHeight(root.right);
        return Math.abs(leftH-leftR)<=1&&isBalanced(root.left)&&isBalanced(root.right);
    }
    方法2
    //判断一棵树是不是平衡二叉树,时间复杂度为O(N)
    public boolean isBalanced2(TreeNode root) {
        return getHeight2(root)>=0;
    }
    // 获取二叉树的高度
    int getHeight2(TreeNode root){
        if(root==null){
            return 0;
        }
        int leftH=getHeight2(root.left);
        int leftR=getHeight2(root.right);
        if(leftH>=0&&leftR>=0&&Math.abs(leftH-leftR)<=1){
            return Math.max(leftH,leftR)+1;
        }else{
            return -1;
        }
    }

 5.对称二叉树

思路:对称二叉树,其左子树的左树与右子树的右树,左子树的右树与右子树的左树也都要对称

//对称二叉树
    public boolean isSymmetric(TreeNode root) {
        if(root==null){
            return true;
        }
        return isSymmetricchild(root.left,root.right);
    }
    public boolean isSymmetricchild(TreeNode leftTree,TreeNode rightTree) {
        if(leftTree!=null&&rightTree==null||leftTree==null&&rightTree!=null){
            return false;
        }
        if(leftTree==null&&rightTree==null){
            return true;
        }
        if(leftTree.val!=rightTree.val){
            return false;
        }
        return isSymmetricchild(leftTree.left,rightTree.right)&&isSymmetricchild(leftTree.right,rightTree.left);
    }

6.二叉树的构建及遍历

import java.util.Scanner;

class TreeNode {
    public char val;
    public TreeNode left;
    public TreeNode right;

    public TreeNode(char val) {
        this.val = val;
    }
}
public class Main {
    public static int i=0;
    public static TreeNode creatTree(String str) {
        TreeNode root=null;
        if(str.charAt(i)!='#'){
            root=new TreeNode(str.charAt(i));
            i++;
            root.left=creatTree(str);
            root.right=creatTree(str);
        }else{
            i++;
        }
        return root;
    }
    //中序遍历
    public static void inOrder(TreeNode root){
        if(root==null){
            return;
        }
        inOrder(root.left);
        System.out.print(root.val+" ");
        inOrder(root.right);
    }
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while (in.hasNextLine()) { 
            String str = in.nextLine();
           TreeNode root =creatTree(str);
           inOrder(root);
        }
    }
}

7.二叉树的分层遍历

思路:可以借助队列来存储,当根节点不为空的时候,将根节点存入队列,当队列不为空的时候,弹出队头元素并打印,判断该节点的左孩子右孩子是否为空,不为空的话入队,如此循环至队列为空,即可实现分层遍历。

//层序遍历
    void leveOrder(TreeNode root){
        Queue<TreeNode> queue=new LinkedList<>();
        if(root!=null){
            queue.offer(root);
        }
        while (!queue.isEmpty()){
            TreeNode cur=queue.poll();
            System.out.print(cur.val+" ");
            if(cur.left!=null){
                queue.offer(cur.left);
            }
            if(cur.right!=null){
                queue.offer(cur.right);
            }
        }
    }
    //分层遍历,以List的方式返回
    public List<List<Character>> levelOrder2(TreeNode root) {
        List<List<Character>> ret=new ArrayList<>();
        if(root==null){
            return ret;
        }
        //借助队列来存取
        Queue<TreeNode> queue=new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()){
            List<Character> curRow=new ArrayList<>();//存入当前行
            int size=queue.size();//获取当前队列元素个数
            while (size!=0){
                TreeNode cur=queue.poll();//弹出队头元素,放入当前行中,同时判断如果该结点有孩子,存入队列
                curRow.add(cur.val);
                if(cur.left!=null){
                    queue.offer(cur.left);
                }
                if(cur.right!=null){
                    queue.offer(cur.right);
                }
                size--;
            }
            ret.add(curRow);
        }
        return ret;
    }

8.给定一个二叉树,找到该树中两个指定结点的最近公共结点

思路:假设p和q有一个是根节点或者不在同一颗子树中,那么直接返回根节点就是这两个结点的最近公共结点;如果p和q在同一颗子树中,那么层级小的为最近公共结点

//给定一个二叉树,找到两个指定结点的最近公共祖先
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root==null){
            return null;
        }
        if(root==p||root==q){
            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;
    }

9.二叉树搜索树转换成排序双向链表

思路:实现排序可以通过中序遍历做到,那我们再同时修改结点的指向就可以实现双向链表,使用一个全局变量prev保存前一个结点,pcur是指当前结点

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
 二叉树搜索树转换成排序双向链表
*/
public class Solution {
    public TreeNode prev=null;
    //中序遍历
    public void Convertchild(TreeNode pcur) {
        if(pcur==null){
            return;
        }
        Convertchild(pcur.left);
        pcur.left=prev;//给当前的pcur数字赋左边的数据,prev保存前一个pcur
        if(prev!=null){//prev==null说明是在叶子结点(该题的第一个结点),如果prev.right就会空指针异常
            prev.right=pcur;//将当前数据赋给前一个数据的右边
        }
        prev=pcur;//修改完指向后将当前结点保存为prev
        Convertchild(pcur.right);
    }
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree==null){
            return null;
        }
        //修改结构
        Convertchild(pRootOfTree);
        TreeNode head=pRootOfTree;
        while(head.left!=null){
            head=head.left;
        }
        return head;
    }
}

10.根据一颗树的前序遍历和中序遍历构造二叉树

思路:前序遍历的第一个结点一定是根节点,拿到根节点后去中序遍历数组中找到相应结点,则该结点之前都是左子树元素,之后都是右子树元素,左子树元素在前序遍历中对应的第一个结点则为左子树的根节点,右子树元素在前序遍历中对应的第一个结点则为由子树的根节点,循环查找即可得出二叉树

/**
 * 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 preindex=0;
    public TreeNode buildTree(int[] preorder, int[] inorder) {
       return buildTreechild(preorder,inorder,0,inorder.length-1);
    }
     public TreeNode buildTreechild(int[] preorder,int[] inorder,int ibegin,int inend) {
         if(ibegin>inend){
             return null;
         }
         TreeNode root=new TreeNode(preorder[preindex]);
         int rootindex=findindex(inorder,preorder[preindex],ibegin,inend);
         preindex++;
         root.left=buildTreechild(preorder,inorder,ibegin,rootindex-1);
         root.right=buildTreechild(preorder,inorder,rootindex+1,inend);
         return root;
    }
    public int findindex(int[] inorder,int key,int ibegin,int inend){
        for(int i=ibegin;i<=inend;i++){
            if(inorder[i]==key){
                return i;
            }
        }
        return -1;
    }
}

11.根据一棵树的中序遍历与后序遍历构造二叉树

思路:后序遍历的最后一个结点一定是根节点,拿到根节点后去中序遍历数组中找到相应结点,则该结点之前都是左子树元素,之后都是右子树元素,左子树元素在后序遍历中对应的最后一个结点则为左子树的根节点,右子树元素在后序遍历中对应的最后一个结点则为由子树的根节点,循环查找即可得出二叉树

/**
 * 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 postindex=0;
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        postindex=postorder.length-1;
        return buildTreechild(postorder,inorder,0,inorder.length-1);
    }
     public TreeNode buildTreechild(int[] postorder,int[] inorder, int ibegin,int inend) {
         if(ibegin>inend){
             return null;
         }
         TreeNode root=new TreeNode(postorder[postindex]);
         int rootindex=findindex(inorder,postorder[postindex],ibegin,inend);
         postindex--;
         root.right=buildTreechild(postorder,inorder,rootindex+1,inend);
         root.left=buildTreechild(postorder,inorder,ibegin,rootindex-1);
         return root;
    }
    public int findindex(int[] inorder,int key,int ibegin,int inend){
        for(int i=ibegin;i<=inend;i++){
            if(inorder[i]==key){
                return i;
            }
        }
        return -1;
    }
}

12.二叉树构建字符串

思路:

  • 如果当前节点有两个孩子,那我们在递归时,需要在两个孩子的结果外都加上一层括号;

  • 如果当前节点没有孩子,那我们不需要在节点后面加上任何括号;

  • 如果当前节点只有左孩子,那我们在递归时,只需要在左孩子的结果外加上一层括号,而不需要给右孩子加上任何括号;
  • 如果当前节点只有右孩子,那我们在递归时,需要先加上一层空的括号 ‘()’ 表示左孩子为空,再对右孩子进行递归,并在结果外加上一层括号。

    //二叉树创建字符串
    public String tree2str(TreeNode root) {
        StringBuilder sb=new StringBuilder();
        if(root==null){
            return new String(sb);
        }
        tree2strchild(root,sb);
        return new String(sb);
    }
    public void tree2strchild(TreeNode t, StringBuilder sb) {
        if(t==null){
            return ;
        }
        sb.append(t.val);
        if(t.left!=null){
            sb.append("(");
            tree2strchild(t.left,sb);
            sb.append(")");
        }else{
            if(t.right==null){
                return;
            }else{
                sb.append("()");//通过判断右为不为空来判断左边是直接返回还是加()
            }
        }
        if(t.right!=null){
            sb.append("(");
            tree2strchild(t.right,sb);
            sb.append(")");
        }else{
            return;
        }
    }

13.二叉树前序遍历

//递归实现前序遍历
void preOrder(TreeNode root){
        if(root==null){
            return;
        }
        System.out.print(root.val+" ");
        preOrder(root.left);
        preOrder(root.right);
    }
//非递归实现前序遍历
public List<Character> preorderTraversal(TreeNode root){
        List<Character> list=new ArrayList<>();
        Stack<TreeNode> stack=new Stack<>();
        TreeNode cur=root;
        while (cur!=null||!stack.empty()) {
            while (cur != null) {
                stack.push(cur);
                list.add(cur.val);
                cur = cur.left;
            }
            TreeNode top = stack.pop();
            cur = top.right;
        }
        return list;
}

14.二叉树中序遍历

//非递归实现中序遍历
    public List<Character> inorderTraversal(TreeNode root) {
        List<Character> list=new ArrayList<>();
        Stack<TreeNode> stack=new Stack<>();
        TreeNode cur=root;
        while (cur!=null||!stack.empty()) {
            while (cur != null) {
                stack.push(cur);
                cur = cur.left;
            }
            TreeNode top = stack.pop();
            list.add(top.val);
            cur=top.right;
        }
        return list;
    }
//递归实现中序遍历
void inOrder(TreeNode root){
        if(root==null){
            return;
        }
        inOrder(root.left);
        System.out.print(root.val+" ");
        inOrder(root.right);
    }

15.二叉树后序遍历

//非递归实现后序遍历
public List<Character> postorderTraversal(TreeNode root) {
     List<Character> list=new ArrayList<>();
        Stack<TreeNode> stack=new Stack<>();
        TreeNode cur=root;
        TreeNode prev=null;
        while (cur!=null||!stack.empty()) {
            while (cur != null) {
                stack.push(cur);
                cur = cur.left;
            }
            TreeNode top = stack.peek();

           if(top.right==null||top.right==prev){
               list.add(top.val);
               prev=top;
               stack.pop();
           }else{
               cur=top.right;
           }
        }
        return list;
}
//递归实现后序遍历
void postOrder(TreeNode root){
        if(root==null){
            return;
        }
        postOrder(root.left);
        postOrder(root.right);
        System.out.print(root.val+" ");
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值