Algorithm Clearance Village - Easily solve the height and depth problems of binary trees

Directory of articles in the Algorithm Clearance Village series



Preface

本系列文章是针对于鱼皮知识星球——编程导航中的算法通关村中的算法进行归纳和总结。 该篇文章讲解的是第八中的白银挑战和黄金挑战———二叉树的深度和高度问题

In this issue, we will mainly look at the issues related to the depth and height of binary trees. In the questions, we will use a lot of recursive ideas to deal with the problems. Therefore, in this issue, we will also review the binary tree problems again. , the basic ideas and construction methods of recursion

After the reverse, how to deal with other nodes originally connected to the node?

Classic linked list reversal methods include head insertion and direct reversal.


1. Maximum depth problem

LeetCode 104:
Given a binary tree root , return its maximum depth.

The maximum depth of a binary tree is the number of nodes on the longest path from the root node to the farthest leaf node.
Insert image description here

Import: root = [3,9,20,null,null,15,7]
Export: 3

We will solve the next few questions through recursive thinking.

step:

  1. For each node, the maximum path starting from it must be the larger path between the left subtree and the right subtree + 1.
  2. If for a node, its left node and right node are both null, then it is a leaf node and the end point of a path. At this time, we only need to return 1.

According to our above ideas, we can easily write the code

    public static int maxD(TreeNode root){
    
    
        if(root.left==null&&root.right==null){
    
    
            return 1;
        }
        int left=0;
        int right=0;
        if(root.left!=null){
    
    
            left= maxD(root.left) + 1;
        }
        if(root.right!=null){
    
    
            right=maxD(root.right)+1;
        }
        return Math.max(left,right);
    }

We can also get a glimpse from this. As long as we understand what recursion has to do each time and think about the termination conditions, it is still very easy to solve general recursion problems.


2. Judgment of Balance Tree

LeetCode 110:
Given a binary tree, determine whether it is a height-balanced binary tree.

In this question, a height-balanced binary tree is defined as:

The absolute value of the height difference between the left and right subtrees of each node of a binary tree does not exceed 1
Insert image description here

Input: root = [3,9,20,null,null,15,7]
Output: true

step:

  1. For each node, first recurse left and right in order to obtain the height of the left subtree and the height of the right subtree. If any one of them returns -1, it means that the left subtree or the right subtree is already unbalanced. , then for this node, it will naturally be unbalanced, just return -1 directly.
  2. If neither is -1, then enter the comparison. If the height difference is <= 1, then the requirement is met. Finally, the largest one is returned and 1 is added. If it is > 1, then it meets the requirement and -1 is returned directly.
  3. If the leaf node is traversed, then there is no way to recurse backwards, just return 1.
    public static int recur(TreeNode root){
    
    

        if(root.left==null&&root.right==null){
    
    
            return 1;
        }
        int left=0;
        int right=0;
        if(root.left!=null)    left = recur(root.left);
        if(left==-1) return -1;
        if(root.right!=null)   right= recur(root.right);
        if(right==-1) return -1;
        return Math.abs(right-left)<=1?Math.max(left,right)+1:-1;
    }

Convert to code

main

3. Minimum depth

LeetCode 111:
Given a binary tree, find its minimum depth.

The minimum depth is the number of nodes on the shortest path from the root node to the nearest leaf node.

Note: Leaf nodes refer to nodes that have no child nodes.
Insert image description here

Import: root = [3,9,20,null,null,15,7]
Export: 2

This minimum depth is similar to the maximum depth we did above. However, when initializing the variable, it must be set to Integer.MAX_VALUE and cannot be set to 0.

step:

  1. For each node, the shortest path starting with it must be the smaller path between the left subtree and the right subtree + 1.
  2. When traversing to the leaf node, there is no way to traverse further, just return 1 directly.

Code:

    public static int minDepth(TreeNode root){
    
    
        if(root==null) return 0;
        if(root.left==null&&root.right==null){
    
    
            return 1;
        }
        int left=Integer.MAX_VALUE,right=Integer.MAX_VALUE;
       if(root.left!=null)  left=minDepth(root.left);
       if(root.right!=null) right=minDepth(root.right);
       return Math.min(left,right)+1;
    }

4. The maximum depth of N-ary tree

LeetCode 559:
Given an N-ary tree, find its maximum depth.

The maximum depth is the total number of nodes on the longest path from the root node to the furthest leaf node.

The N-ary tree input is a serialized representation in level-order traversal, with each set of child nodes separated by null values ​​(see example).
Insert image description here

Input: root = [1,null,3,2,4,null,5,6]
Output: 3

Here it just replaces the original binary tree with an N-ary tree. Its essence is still the same, except that it only needs to compare two paths. Here, it needs to compare N paths. Everything else is the same.

step:

  1. For each node, the maximum path starting with it is the largest path among its N byte points starting with the path + 1.
  2. If the traversed node is a leaf node, it means that it cannot be traversed any further, just return 1.
    public static int maxDepth_N(NTreeNode root) {
    
    
        if(root==null) return 0;
        if(root.children==null){
    
    
            return 1;
        }
        int max=0;
        for (NTreeNode child : root.children) {
    
    
            max=Math.max(maxDepth_N(child),max);
        }
        return max+1;
    }

5. The issue of recent common ancestors

Given a binary tree, find the nearest common ancestor of two specified nodes in the tree.

The definition of the nearest common ancestor in Baidu Encyclopedia is: "For two nodes p and q of a rooted tree T, the nearest common ancestor is represented as a node x, such that x is the ancestor of p and q and the depth of x is as large as possible (a A node can also be its own ancestor)."

Insert image description here

Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
Output :3
Explanation: The nearest common ancestor of node 5 and node 1 is node 3.

This question is more difficult, because in the recursion, it is difficult to distinguish what should be done at each level. Let's look at it first. The question requires us to find the nearest common ancestor of the two specified nodes. By analyzing the question, we will find that the most recent common ancestors are:

  1. one of the two nodes themselves
  2. The first forked node in front of the two nodes

So for this question, we can think about it this way

  1. For each node, if it is one of the current nodes, it means that it has found the target node, and there is no need to search further. It directly returns the value of the target node, indicating that for this branch , he finds the correct path and the nearest ancestor is the returned value.
  2. On the contrary, if the traversal is still not found at the end, then null is returned directly, which means that this branch has no target element and can be discarded directly.
  3. Then when the left and right nodes are returned, it is time to compare. If the left side is null and the right side is null, it means that for this node, there is no target node in its left subtree and right subtree, so just return null directly. Got it
  4. If the left side is null and the right side is not null, then return the element on the right side.
  5. Similarly, if the right side is null and the left side is not null, then return the element on the left
  6. If both the left and right sides are returned, then the node is the nearest common ancestor, then return itself

We can easily follow the code and follow the idea.

    public static TreeNode lowestCommonAncestor(TreeNode node,TreeNode p, TreeNode q){
    
    
        //这个并不是一个将节点连起来的操作,只是去看一看该节点的左树和右树,有没有符合情况的,如果left是null。说明左树没有符合情况的,right也同理。
        //如果左边返回的不是努null,那就说明左侧有,并且返回的还要啥最近的节点。
        if(node==null||node.val==p.val||node.val==q.val) return node;
        TreeNode left = lowestCommonAncestor(node.left,p,q);
        TreeNode right = lowestCommonAncestor(node.right,  p,q);
        if(left==null&&right==null) return null;
        if(left==null) return right;
        if(right==null) return left;
        return node;
    }

Summarize

After you carefully analyze the above questions, you will find that the above questions all have the same idea. For each node, you need to traverse the left node and the right node separately, and compare these two The results are compared and processed, and finally returned. You must analyze the questions in this section carefully. These are not only basic questions about binary trees, but also good questions for developing our recursive thinking.

That concludes this section. I'm Mayphyr, from a little bit to a billion points, see you next time

Guess you like

Origin blog.csdn.net/aaaaaaaa273216/article/details/132908160