二叉树的进阶以及OJ题

1.两颗相同的树

        给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。100. 相同的树 - 力扣(LeetCode)

class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        if((p==null && q!=null) || (p!=null) && (q==null)){
            return false;
        }

        if(p==null&&q==null){
            return true;
        }

        if(p.val!=q.val){
            return false;
        }
        return (isSameTree(p.left,q.left)&&isSameTree(p.right,q.right));
    }
}

题解:先判断根节点的值是否相同,再利用递归分别判断第一颗树与第二课树的左子树是否一一对应,右子树的值也是否一一对应。

2.另一颗树的子树:

        给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。572. 另一棵树的子树 - 力扣(LeetCode)

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

    }
    
    public boolean isSameTree(TreeNode p, TreeNode q) {
        if((p==null && q!=null) || (p!=null) && (q==null)){
            return false;
        }

        if(p==null&&q==null){
            return true;
        }

        if(p.val!=q.val){
            return false;
        }
        return (isSameTree(p.left,q.left)&&isSameTree(p.right,q.right));
}
}

题解:从根节点开始,依次往下递归判断子树是否有相同的区段(用到上一题的判断两棵树是否相同)。

3.翻转二叉树:

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。226. 翻转二叉树 - 力扣(LeetCode)

class Solution {
    public TreeNode invertTree(TreeNode root) {
        TreeNode tmp;
    if(root == null){
        return null;
    }
        tmp = root.left;
        root.left = root.right;
        root.right = tmp;
    
    invertTree(root.left);
    invertTree(root.right);
    return root;

    }
}

题解:同样利用递归的思路,遇到空节点的时候返回,依次往下递归,左子树翻转和右子树翻转。

4.平衡二叉树:

给定一个二叉树,判断它是否是 平衡二叉树  110. 平衡二叉树 - 力扣(LeetCode)

class Solution {
    public boolean isBalanced(TreeNode root) {
        if(root == null){
            return true;
        }

        return Math.abs(getHeight(root.left)-getHeight(root.right))<=1&&isBalanced(root.left)&&isBalanced(root.right);
    }
    public int getHeight(TreeNode root){
        if(root == null){
            return 0;
        }
        int right = getHeight(root.right);
        int left = getHeight(root.left);
        return Math.max(right,left) + 1;
    }
}

题解:首先在根节点的时候判断左子树和右子树高度差是否大于1,再用递归的思想分别判断左右子树是否同样满足条件。

5.对称二叉树:

给你一个二叉树的根节点 root , 检查它是否轴对称。101. 对称二叉树 - 力扣(LeetCode)

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root == null){
            return true;
        }
        return isSymmetricchild(root.left, root.right);
    }
    
    public boolean isSymmetricchild(TreeNode rootleft, TreeNode rootright){
        // 两个节点都为null,对称
        if(rootleft == null && rootright == null){
            return true;
        }
        // 一个为null,一个不为null,不对称
        if(rootleft == null || rootright == null){
            return false;
        }
        // 节点值不相等,不对称
        if(rootleft.val != rootright.val){
            return false;
        }
        // 递归检查子节点:左节点的左孩子对应右节点的右孩子,左节点的右孩子对应右节点的左孩子
        return isSymmetricchild(rootleft.left, rootright.right) 
            && isSymmetricchild(rootleft.right, rootright.left);
    }
}

6.遍历二叉树:

编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。

import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
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 int i = 0;

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextLine()) { // 改为判断是否有下一行字符串
            String str = in.nextLine();
            if (str.isEmpty()) continue; // 跳过空行
            i = 0; // 重置索引,处理多个测试用例
            TreeNode root = creatTree(str);
            orderTree(root);
            System.out.println(); // 每个测试用例输出后换行
        }
    }

    /**
     * 根据先序遍历字符串创建二叉树
     * 其中'#'表示空节点
     */
    public static TreeNode creatTree(String str){
        // 检查是否已遍历完所有字符
        if (i >= str.length()) {
            return null;
        }
        
        char ch = str.charAt(i);
        
        // 如果当前字符是'#',表示空节点
        if(ch == '#'){
            i++; // 移动到下一个字符
            return null;
        }
        
        // 创建当前节点
        TreeNode root = new TreeNode(ch);
        i++; // 移动到下一个字符
        
        // 递归创建左子树
        root.left = creatTree(str);
        // 递归创建右子树
        root.right = creatTree(str);
        
        return root;
    }

    /**
     * 中序遍历二叉树并打印节点值
     */
    public static void orderTree(TreeNode root){
        if(root == null){
            return;
        }
        orderTree(root.left); // 遍历左子树
        System.out.print(root.val + " "); // 打印当前节点
        orderTree(root.right); // 遍历右子树
    }
}

7.二叉树的分层遍历

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。102. 二叉树的层序遍历 - 力扣(LeetCode)

先脱离这道题目去思考一下,我们可以使用队列(queue)来完成分层遍历

public void levelOrder(TreeNode root){
        if(root == null){
            return;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        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);
            }
        }
    }
  1. 边界处理

    • 如果根节点rootnull,直接返回,避免空指针异常
  2. 队列初始化

    • 使用Queue(具体实现为LinkedList)来辅助层序遍历
    • 首先将根节点加入队列作为遍历的起点
  3. 遍历过程

    • 外层循环:只要队列不为空就继续遍历
    • 出队一个节点cur,并打印其值
    • 如果该节点有左子树,将左子节点入队
    • 如果该节点有右子树,将右子节点入队
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);//A
        while (!queue.isEmpty()) {
            List<Character> curRow = new ArrayList<>();
            /*记录每一行的数据个数*/
            int size = queue.size();//4

            while (size != 0) {
                TreeNode cur = queue.poll();
                curRow.add(cur.val);
                //System.out.print(cur.val + " ");
                if (cur.left != null) {
                    queue.offer(cur.left);
                }
                if (cur.right != null) {
                    queue.offer(cur.right);
                }
                size--;
            }
            ret.add(curRow);
        }
        return ret;
    }
  1. 初始化

    • 创建一个二维列表ret用于存储最终结果
    • 如果根节点rootnull,直接返回空列表
  2. 队列应用

    • 使用Queue来实现层序遍历,首先将根节点加入队列
  3. 层级遍历

    • 外层循环:只要队列不为空就继续遍历
    • 记录当前层的节点数量size(这是关键,确保我们只处理当前层的节点)
    • 内层循环:处理当前层的所有节点(循环size次)
      • 出队一个节点并将其值加入当前层的列表
      • 如果该节点有左子树,将左子节点入队
      • 如果该节点有右子树,将右子节点入队
      • 减少当前层节点计数
  4. 结果收集

    • 每处理完一层,就将当前层的列表加入结果集ret
    • 最终返回整个结果集

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值