二叉树的最小深度、完全二叉树的节点个数、平衡二叉树、路径总和、从中序与后序遍历序列构造二叉树

111. 二叉树的最小深度

这题与求最大深度相似,依然是使用后序遍历,但是要注意,我们不能直接把最大深度中的max改为min直接提交这样是不对的。

如图,若直接改为min,那么返回的就是1,但实际上最小深度是到叶节点的最小距离,所以应该是3。代码如下:

复制代码
class Solution {
    public int minDepth(TreeNode root) {
        return getHeight(root);
    }
    public int getHeight(TreeNode root){
        if(root==null){
            return 0;
        }
        int leftHeight=getHeight(root.left);
        int rightHeight=getHeight(root.right);
        if(root.left==null&&root.right!=null){
            return 1+rightHeight;
        }else if(root.left!=null&&root.right==null){
            return 1+leftHeight;
        }
        int result=1+Math.min(leftHeight,rightHeight);
        return result;
    }
}

222. 完全二叉树的节点个数

这道题有两种方法,一种是按照普通树的思路,这种方法很简单,把左右子树的数量计算一下相加就行;另一种是完全二叉树的思路,我们需要对比,比如左子树的左侧和右侧深度是否相同,如果相同就是一个小的完全二叉树,完全二叉树的公式是2^深度-1,不相同就接着比较。但这种方法相对来说复杂一点,我这里只写了普通树的思路,代码如下:

复制代码
class Solution {
    public int countNodes(TreeNode root) {
        return getNum(root);
    }
    public int getNum(TreeNode root){
        if(root==null){
            return 0;
        }
        int leftNum=getNum(root.left);
        int rightNum=getNum(root.right);
        int result=leftNum+rightNum+1;
        return result;
    }
}

110. 平衡二叉树

根据平衡二叉树的性质,我们把左右子树的高度相减即可,大于1的返回-1,代码如下:

复制代码
class Solution {
    public boolean isBalanced(TreeNode root) {
        int a=getHeight(root);
        if(a==-1){
            return false;
        }
        return true;
    }
    public int getHeight(TreeNode node){
        if(node==null){
            return 0;
        }
        int leftHeigth=getHeight(node.left);
        if(leftHeigth==-1){
            return -1;
        }
        int rightHeight=getHeight(node.right);
        if(rightHeight==-1){
            return -1;
        }
        int result;
        if(Math.abs(leftHeigth-rightHeight)>1){
            result=-1;
        }else{
            result=1+Math.max(leftHeigth,rightHeight);
        }
        return result;
    }
}

112. 路径总和

我们可以采用相减的办法,把目标值减去孩子的值,在叶子节点处且减为0时则返回true,代码如下:

复制代码
class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        return traversal(root,targetSum);
    }
    public boolean traversal(TreeNode node,int count){
        if(node==null)
        return false;
        count-=node.val;
        if(node.left==null&&node.right==null&&count==0){
            return true;
        }
        if(node.left==null&&node.right==null&&count!=0){
            return false;
        }
        if(node.left!=null){
            if(traversal(node.left,count)==true){
                return true;
            }
        }
        if(node.right!=null){
            if(traversal(node.right,count)==true){
                return true;
            }
        }
        return false;
    }
}

首先在 hasPathSum 方法中调用递归函数 traversal,从根节点开始遍历整棵树,并把目标路径和 targetSum 传入。

递归函数 traversal(TreeNode node, int count) 的含义是:当前遍历到 node 节点时,还需要凑出的路径和为 count。函数首先判断当前节点是否为空,如果为空说明这条路径不存在,直接返回 false

如果节点不为空,就执行 count -= node.val,表示当前节点已经被访问,因此从剩余目标值中减去当前节点的值,此时 count 表示从当前节点继续向下遍历还需要凑出的路径和。接着判断当前节点是否为叶子节点,如果当前节点既没有左孩子也没有右孩子,并且此时 count == 0,说明从根节点到该叶子节点的路径和正好等于 targetSum,函数返回 true;如果到达叶子节点但 count 不为 0,说明这条路径不满足条件,返回 false

如果当前节点不是叶子节点,则继续递归遍历其子树,先判断左子树,如果左子树中存在满足条件的路径就直接返回 true;如果左子树没有找到,则继续判断右子树,如果右子树中存在满足条件的路径同样返回 true。当左右子树都没有找到满足条件的路径时,函数最终返回 false

106. 从中序与后序遍历序列构造二叉树

这道题是一个中等难度的题,如何从中序遍历和后序遍历中得出二叉树呢?如下:

复制代码
inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]

中序遍历是:左中右,后序遍历是:左右中。由此我们可以得知,3是根节点,那么看前序遍历,以3为分界线,左边是左子树,右边是右子树。在后续遍历中:15,7,20可以得知20是中间的数,那么在前序遍历中,15在左,7在右。

我们写代码要分为以下几步:

1.前/后序数组长度为0,则字数为空

2.后序数组最后一个数为根节点

3.寻找根节点在前序数组中的位置,做切割

4.切割前序数组

5.切割中序数组

6.递归处理区间

代码如下:

复制代码
class Solution {
    public TreeNode buildTree(int[] inorder, int[] postorder) {
       return traversal(inorder,postorder);
    }
    public TreeNode traversal(int[] inorder,int[] postorder){
         if(postorder.length==0){
            return null;
        }
        int rootValue=postorder[postorder.length-1];
        TreeNode root=new TreeNode(rootValue);
        if(postorder.length==1){
            return root;
        }
        int index=0;
        for(index=0;index<inorder.length;index++){
            if(inorder[index]==rootValue){
                break;
            }
        }
        int leftSize=index;
        int[] leftInorder=new int[leftSize];
        int[] rightInorder=new int[inorder.length-leftSize-1];

        int[] leftPostorder=new int[leftSize];
        int[] rightPostorder=new int[postorder.length-leftSize-1];

        for(int i=0;i<leftSize;i++){
            leftInorder[i]=inorder[i];
            leftPostorder[i]=postorder[i];
        }
        for(int i=index+1;i<inorder.length;i++){
            rightInorder[i-index-1]=inorder[i];
        }
        for (int i = leftSize; i < postorder.length - 1; i++) {
            rightPostorder[i - leftSize] = postorder[i];
        }
        root.left=traversal(leftInorder,leftPostorder);
        root.right=traversal(rightInorder,rightPostorder);
        return root;
    }
}

traversal 中,递归的终止条件是后序数组长度为 0,此时没有节点可构建,直接返回 null。接着,取后序数组的最后一个元素作为根节点值 rootValue,并创建一个 TreeNode 实例作为当前子树的根节点。如果后序数组长度为 1,说明当前子树只有根节点,直接返回即可。

然后,在中序数组中找到根节点的位置 index,这个位置把中序数组分为左子树和右子树两部分。左边长度为 leftSize = index,右边长度为 inorder.length - leftSize - 1。根据这个长度,分别创建左子树和右子树的中序数组 leftInorderrightInorder 以及后序数组 leftPostorderrightPostorder

接下来,通过循环给左子树数组赋值:左子树的中序数组取中序数组前 leftSize 个元素,左子树后序数组取后序数组前 leftSize 个元素(不包含最后的根节点)。右子树的中序数组取中序数组从 index+1 到末尾的元素,右子树后序数组取后序数组从 leftSize 到倒数第二个元素(最后一个是根节点)。

最后,递归调用 traversal 构建左子树和右子树,并分别赋给 root.leftroot.right,最终返回构建好的根节点。通过这种递归拆分和数组复制的方法,整个二叉树就可以按照原始中序和后序遍历序列重建出来。

相关推荐
想进个大厂2 小时前
代码随想录day63 64 65 66 图论08 09 10 11
c++·算法·图论
云泽8082 小时前
蓝桥杯算法精讲:双指针算法四大经典例题深度剖析
算法·职场和发展·蓝桥杯
AD钙奶-lalala2 小时前
SpringBoot 4.0.3配置Swagger
java·spring boot·后端
小龙报2 小时前
【算法通关指南:算法基础篇】二分算法: 1.A-B 数对 2.烦恼的高考志愿
c语言·开发语言·数据结构·c++·vscode·算法·二分
seven97_top2 小时前
NIO:解开非阻塞I/O高并发编程的秘密
java
小六溜了2 小时前
模块二十.双列集合
java
23.2 小时前
【Java】NIO 中的多路复用(Selector / Channel)机制
java·面试·nio
yong99902 小时前
NNDA、PDA、JPDA、IMM数据关联算法MATLAB实现
开发语言·算法·matlab