剑指offer——树

这篇博客主要介绍了《剑指Offer》中关于二叉树的多个问题,包括平衡二叉树的判断、二叉搜索树的后序遍历序列判断、从上到下打印二叉树的各种方式,以及二叉树的镜像操作。通过示例和解析过程,展示了如何使用Java高效地解决这些问题。
摘要由CSDN通过智能技术生成

剑指 Offer 55 - II. 平衡二叉树
输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。

示例 1:
给定二叉树 [3,9,20,null,null,15,7]

	3
   / \
  9  20
    /  \
   15   7

返回 true 。

示例 2:
给定二叉树 [1,2,2,3,3,null,null,4,4]

 	   1
      / \
     2   2
    / \
   3   3
  / \
 4   4

返回 false 。
解析过程:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isBalanced(TreeNode root) {
         //对于当前遍历到的节点,首先计算左右子树的高度,如果左右子树的高度差是否不超过 1,再分别递归地遍历左右子节点,并判断左子树和右子树是否平衡。
        //递归
        if(root==null){
            return true;
        }
        if(root.left==null && root.right==null){
            return true;
        }
        return Math.abs(depth(root.left)-depth(root.right))<=1 && isBalanced(root.left) && isBalanced(root.right);
    }
    //用于计算二叉树中的任意一个节点node的高度
    public int depth(TreeNode node){
        if(node == null){
            return 0;
        }
        int Left=depth(node.left);
        int Right=depth(node.right);
        return Math.max(Left,Right)+1;
    }
}

结果:
执行用时:1 ms, 在所有 Java 提交中击败了71.73%的用户
内存消耗:38.5 MB, 在所有 Java 提交中击败了48.11%的用户
通过测试用例:227 / 227

剑指 Offer 33. 二叉搜索树的后序遍历序列
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。

参考以下这颗二叉搜索树:

 	 5
    / \
   2   6
  / \
 1   3

示例 1:
输入: [1,6,3,2,5]
输出: false

示例 2:
输入: [1,3,2,6,5]
输出: true
解析过程:

class Solution {
    /*
    后序遍历定义: 左子树  右子树  根节点,即遍历顺序为 左、右、根
    二叉搜索树定义: 左子树中所有节点的值 < 根节点的值;右子树中所有节点的值 > 根节点的值;其左、右子树也分别为二叉搜索树
    */
    public boolean verifyPostorder(int[] postorder) {
        return verify(postorder,0,postorder.length-1);
    }
    public boolean verify(int[] postorder,int L,int R){
        //终止条件: 当L >= R ,说明此子树节点数量≤1 ,无需判别正确性,因此直接返回 true;
        if(L >= R){
            return true;
        }
        /*
        1.最后一个节点为根节点,要先通过找到第一个大于根节点的节点,划分左右子树,索引记为value.
        2.判断是否为二叉搜索树:
            1)左子树区间 [L,value - 1]内的所有节点都应< postorder[R]。而第 1.划分左右子树 步骤已经保证左子树区间的正确性,因此只需要判断右子树区间即可。
            2)右子树区间 [value, R-1]内的所有节点都应> postorder[R]。实现方式为遍历,当遇到≤postorder[R] 的节点则跳出;则可通过index==R判断是否为二叉搜索树。
        3.递归 
        */
        int index=L;
        while(postorder[index]<postorder[R]){
            index++;
        }
        int value=index;
        while(postorder[index]>postorder[R]){
            index++;
        }
        //所有子树都需正确才可判定正确
        return index==R && verify(postorder,L,value-1) && verify(postorder,value,R-1);
    }
}

结果:
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:36 MB, 在所有 Java 提交中击败了30.48%的用户
通过测试用例:23 / 23

剑指 Offer 32 - I. 从上到下打印二叉树
从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。
例如:
给定二叉树: [3,9,20,null,null,15,7],

 	3
   / \
  9  20
    /  \
   15   7

返回:
[3,9,20,15,7]

提示:节点总数 <= 1000
解析过程:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    //因为最后是以数组的形式输出,但是数组不能直接添加元素,所以需要一个可以改变大小的数组为ArrayList
    //若要从上到下,从左到右打印二叉树的每个节点,需要采用层次遍历
    public int[] levelOrder(TreeNode root) {
        List<Integer> list=new ArrayList<>();
        if(root==null){
            return new int[0];
        }
        Queue<TreeNode> queue=new LinkedList<>();
        queue.offer(root);
        while(! queue.isEmpty()){
            int size=queue.size();
            for(int i=0;i<size;i++){
                TreeNode cur=queue.poll();
                list.add(cur.val);
                if(cur.left!=null){
                    queue.offer(cur.left);
                }
                if(cur.right!=null){
                    queue.offer(cur.right);
                }
            }
        }
        int[] res=new int[list.size()];
        for(int i=0;i<list.size();i++){
            res[i]=list.get(i);
        }
        return res;
    }
}

结果:
执行用时:1 ms, 在所有 Java 提交中击败了98.13%的用户
内存消耗:38.5 MB, 在所有 Java 提交中击败了59.80%的用户
通过测试用例:34 / 34

剑指 Offer 32 - II. 从上到下打印二叉树 II
从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。

例如:
给定二叉树: [3,9,20,null,null,15,7],

 	3
   / \
  9  20
    /  \
   15   7

返回其层次遍历结果:
[
[3],
[9,20],
[15,7]
]
提示:节点总数 <= 1000
解析过程:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        //采用层次遍历
        List<List<Integer>> list=new ArrayList<>();
        if(root == null){
            return list;
        }
        Queue<TreeNode> queue=new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            int size=queue.size();
            List<Integer> level=new ArrayList<>();
            for(int i=0;i<size;i++){
                TreeNode cur=queue.poll();
                level.add(cur.val);
                if(cur.left!=null){
                    queue.offer(cur.left);
                }
                if(cur.right!=null){
                    queue.offer(cur.right);
                }
            }
            list.add(level);
        }
        return list;
    }
}

结果:
执行用时:1 ms, 在所有 Java 提交中击败了93.59%的用户
内存消耗:38.6 MB, 在所有 Java 提交中击败了53.08%的用户
通过测试用例:34 / 34

剑指 Offer 32 - III. 从上到下打印二叉树 III
请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。

例如:
给定二叉树: [3,9,20,null,null,15,7],

	3
   / \
  9  20
    /  \
   15   7

返回其层次遍历结果:
[
[3],
[20,9],
[15,7]
]
解析过程:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        //层序遍历
        //此处需要一个双端队列,对当前层节点的存储需要设置一个flag记录是从左至右还是从右至左的
        //从左至右:将遍历到的节点插入双端队列的末尾   offerLast()方法用于在此双端队列的最后添加给定元素
        //从右至左:将遍历到的节点插入双端队列的头部   offerFirst()方法用于将给定元素添加到此双端队列的前面

        List<List<Integer>> list=new ArrayList<>();
        if(root==null){
            return list;
        }
        Queue<TreeNode> queue=new LinkedList<>();
        queue.offer(root);
        boolean flag=true;
        while(!queue.isEmpty()){
            int size=queue.size();
            Deque<Integer> DQ=new ArrayDeque<>();
            for(int i=0;i<size;i++){
                TreeNode cur=queue.poll();
                if(flag){
                    DQ.offerLast(cur.val);
                }else{
                    DQ.offerFirst(cur.val);
                }
                if(cur.left!=null){
                    queue.offer(cur.left);
                }
                if(cur.right!=null){
                    queue.offer(cur.right);
                }
            }
            list.add(new ArrayList<Integer>(DQ));
            flag=!flag;
        }
        return list;
    }
}

结果:
执行用时:2 ms, 在所有 Java 提交中击败了7.59%的用户
内存消耗:38.4 MB, 在所有 Java 提交中击败了81.77%的用户
通过测试用例:34 / 34

剑指 Offer 27. 二叉树的镜像
请完成一个函数,输入一个二叉树,该函数输出它的镜像。

示例 1:

     4
   /   \
  2     7
 / \   / \
1   3 6   9

输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]

 	 4
   /   \
  7     2
 / \   / \
9   6 3   1

限制:
0 <= 节点个数 <= 1000
解析过程:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    //递归  从根节点开始,递归地对树进行遍历,并从叶子节点先开始翻转得到镜像。将每个节点的左右子树进行交换
    public TreeNode mirrorTree(TreeNode root) {
        if(root == null){
            return null;
        }
        DFS(root);
        return root;
    }
    public TreeNode DFS(TreeNode node){
        if(node == null){
            return null;
        }
        TreeNode Temp1=DFS(node.left);
        TreeNode Temp2=DFS(node.right);
        node.left=Temp2;
        node.right=Temp1;
        return node;
    }
}

结果:
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:35.7 MB, 在所有 Java 提交中击败了66.03%的用户
通过测试用例:68 / 68
方法二:

/**
 * 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 TreeNode invertTree(TreeNode root) {
        //递归,先交换一下左右节点,然后再递归的交换左节点,右节点 
        
        //递归函数的终止条件,节点为空时返回
        if(root == null){
            return null;
        }
        //当前节点的左右子树进行交换
        TreeNode temp=null;
        temp=root.left;
        root.left=root.right;
        root.right=temp;
        //递归
        TreeNode left=invertTree(root.left);
        TreeNode right=invertTree(root.right);
        
        return root;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值