7, Binary tree (12): balanced binary tree

Force button topic link (opens new window)

Given a binary tree, judge whether it is a highly balanced binary tree. In this problem, a highly balanced binary tree is defined as a binary tree with each node   The absolute value of the height difference between the left and right subtrees of does not exceed 1.

Example 1:

Given binary tree [3,9,20,null,null,15,7]

Returns true.

Example 2:

Given binary tree [1,2,2,3,3,null,null,4,4]

  Returns false.

1, Digression

At first glance, this topic and 104. Maximum depth of binary tree   (opens new window) It's very similar. In fact, it's very different.

A wave of concepts is emphasized here:

  • Depth of binary tree node: refers to the number of edges of the longest simple path from the root node to the node.
  • Height of binary tree node: refers to the number of edges of the longest simple path from this node to the leaf node.

However, the depth and height emphasized in leetcode are obviously calculated according to nodes, as shown in the figure:

  Whether the depth of the root node is 1 or 0 has different standards in different places. The title of leetcode takes the node as one degree, that is, the depth of the root node is 1. However, Wikipedia defines the edge as one degree, that is, the depth of the root node is 0. For the time being, we will take leetcode as the standard (after all, we should brush the questions on it).

        Because the depth can be checked from top to bottom, it needs pre order traversal (left and right), while the height can only be checked from bottom to top, so it can only be post order traversal (left and right middle). Some students must be confused.

        Why? 104. Maximum depth of binary tree   (opens new window) Is the maximum depth of the binary tree, also using post order traversal. That's because the logic of the code is actually to find the height of the root node, and the height of the root node is the maximum depth of the tree, so post order traversal can be used. stay 104. Maximum depth of binary tree   (opens new window) In, if the maximum depth of the binary tree is really obtained, the code should be written as follows: (preorder traversal)

class Solution {
public:
    int result;
    void getDepth(TreeNode* node, int depth) {
        result = depth > result ? depth : result; // in

        if (node->left == NULL && node->right == NULL) return ;

        if (node->left) { // Left
            depth++;    // Depth + 1
            getDepth(node->left, depth);
            depth--;    // Backtracking, depth-1
        }
        if (node->right) { // right
            depth++;    // Depth + 1
            getDepth(node->right, depth);
            depth--;    // Backtracking, depth-1
        }
        return ;
    }
    int maxDepth(TreeNode* root) {
        result = 0;
        if (root == 0) return result;
        getDepth(root, 1);
        return result;
    }
};

It can be seen that the traversal order of the previous order (middle left and right) is used, which is the real logic of seeking depth!

Note that the above code is to reflect the details. The code is simplified as follows:

class Solution {
public:
    int result;
    void getDepth(TreeNode* node, int depth) {
        result = depth > result ? depth : result; // in
        if (node->left == NULL && node->right == NULL) return ;
        if (node->left) { // Left
            getDepth(node->left, depth + 1);
        }
        if (node->right) { // right
            getDepth(node->right, depth + 1);
        }
        return ;
    }
    int maxDepth(TreeNode* root) {
        result = 0;
        if (root == 0) return result;
        getDepth(root, 1);
        return result;
    }
};

2, Idea of this topic

two point one   recursion

At this time, you should understand that since the requirements are relatively high, it must be traversal in sequence.

Recursive three-step analysis:

1. Specify the parameters and return values of recursive functions

If the parameter is the incoming node pointer, no other parameters need to be passed. The return value should return the depth of the incoming node as the root node tree. So how to mark whether the difference between the left and right subtrees is greater than 1. If the binary tree with the current incoming node as the root node is no longer a binary balanced tree and returns the height, it is meaningless. Therefore, if it is no longer a binary balanced tree, you can return - 1 to mark that it does not comply with the rules of the balanced tree.

The code is as follows:

// -1 indicates that it is not a balanced binary tree, otherwise the return value is the height of the tree with this node as the root node
int getDepth(TreeNode* node)

2. Clear termination conditions

In the process of recursion, if an empty node is still encountered, it will terminate and return 0, indicating that the current node is the root node and the height of the tree is 0;

The code is as follows:

if (node == NULL) {
    return 0;
}

3. Clarify the logic of single-layer recursion

How to judge whether the binary tree with the current incoming node as the root node is a balanced binary tree? Of course, it is the difference between the height of the left subtree and the height of the right subtree. Calculate the height of the left and right subtrees respectively, and then if the difference is less than or equal to 1, return the height of the current binary tree; otherwise, return - 1, indicating that it is no longer a binary tree.

The code is as follows:

int leftDepth = depth(node->left); // Left
if (leftDepth == -1) return -1;
int rightDepth = depth(node->right); // right
if (rightDepth == -1) return -1;

int result;
if (abs(leftDepth - rightDepth) > 1) {  // in
    result = -1;
} else {
    result = 1 + max(leftDepth, rightDepth); // The maximum height with the current node as the root node
}

return result;

The code is simplified as follows:

int leftDepth = getDepth(node->left);
if (leftDepth == -1) return -1;
int rightDepth = getDepth(node->right);
if (rightDepth == -1) return -1;
return abs(leftDepth - rightDepth) > 1 ? -1 : 1 + max(leftDepth, rightDepth);

At this time, the recursive function has been written. This recursive function passes in the node pointer and returns the height of the binary tree with this node as the root node. If it is not a binary balanced tree, it returns - 1.

The overall code of getDepth is as follows:

int getDepth(TreeNode* node) {
    if (node == NULL) {
        return 0;
    }
    int leftDepth = getDepth(node->left);
    if (leftDepth == -1) return -1;
    int rightDepth = getDepth(node->right);
    if (rightDepth == -1) return -1;
    return abs(leftDepth - rightDepth) > 1 ? -1 : 1 + max(leftDepth, rightDepth);
}

Finally, the overall recursive code of this problem is as follows:

class Solution {
public:
    // Returns the height of the binary tree with this node as the root node. If it is not a binary search tree, it returns - 1
    int getDepth(TreeNode* node) {
        if (node == NULL) {
            return 0;
        }
        int leftDepth = getDepth(node->left);
        if (leftDepth == -1) return -1; // It shows that the left subtree is no longer a binary balanced tree
        int rightDepth = getDepth(node->right);
        if (rightDepth == -1) return -1; // It shows that the right subtree is no longer a binary balanced tree
        return abs(leftDepth - rightDepth) > 1 ? -1 : 1 + max(leftDepth, rightDepth);
    }
    bool isBalanced(TreeNode* root) {
        return getDepth(root) == -1 ? false : true;
    }
};

2.2 iteration

stay 104. Maximum depth of binary tree   (opens new window) In, we can use sequence traversal to calculate depth, but we can't directly use sequence traversal to calculate height, which reflects the difference between height and depth. The iterative method of this problem can first define a function, which is specially used to calculate the height. This function finds the height of each node through the post order traversal of stack simulation (in fact, it finds the height by finding the maximum depth of the incoming node as the root node)

The code is as follows:

// The maximum depth of cur node is the height of cur
int getDepth(TreeNode* cur) {
    stack<TreeNode*> st;
    if (cur != NULL) st.push(cur);
    int depth = 0; // Recording depth
    int result = 0;
    while (!st.empty()) {
        TreeNode* node = st.top();
        if (node != NULL) {
            st.pop();
            st.push(node);                          // in
            st.push(NULL);
            depth++;
            if (node->right) st.push(node->right);  // right
            if (node->left) st.push(node->left);    // Left

        } else {
            st.pop();
            node = st.top();
            st.pop();
            depth--;
        }
        result = result > depth ? result : depth;
    }
    return result;
}

Then use the stack to simulate the preorder traversal. When traversing each node, judge whether the height of the left and right children is consistent. The code is as follows:

bool isBalanced(TreeNode* root) {
    stack<TreeNode*> st;
    if (root == NULL) return true;
    st.push(root);
    while (!st.empty()) {
        TreeNode* node = st.top();                       // in
        st.pop();
        if (abs(getDepth(node->left) - getDepth(node->right)) > 1) { // Judge whether the height of left and right children is consistent
            return false;
        }
        if (node->right) st.push(node->right);           // Right (empty nodes are not stacked)
        if (node->left) st.push(node->left);             // Left (empty nodes are not stacked)
    }
    return true;
}

The overall code is as follows:

class Solution {
private:
    int getDepth(TreeNode* cur) {
        stack<TreeNode*> st;
        if (cur != NULL) st.push(cur);
        int depth = 0; // Recording depth
        int result = 0;
        while (!st.empty()) {
            TreeNode* node = st.top();
            if (node != NULL) {
                st.pop();
                st.push(node);                          // in
                st.push(NULL);
                depth++;
                if (node->right) st.push(node->right);  // right
                if (node->left) st.push(node->left);    // Left

            } else {
                st.pop();
                node = st.top();
                st.pop();
                depth--;
            }
            result = result > depth ? result : depth;
        }
        return result;
    }

public:
    bool isBalanced(TreeNode* root) {
        stack<TreeNode*> st;
        if (root == NULL) return true;
        st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();                       // in
            st.pop();
            if (abs(getDepth(node->left) - getDepth(node->right)) > 1) {
                return false;
            }
            if (node->right) st.push(node->right);           // Right (empty nodes are not stacked)
            if (node->left) st.push(node->left);             // Left (empty nodes are not stacked)
        }
        return true;
    }
};

Of course, the iterative method for this problem is actually very inefficient, because there is no good simulation of the backtracking process, so the iterative method has a lot of repeated calculations. Although theoretically all recursion can be implemented iteratively, some scenarios may be more difficult.

For example: we all know that backtracking is actually recursive, but few people use iterative methods to implement backtracking algorithms!

Because the backtracking algorithm is already very complex recursion. If you are using iteration, you will find yourself in trouble, and the efficiency is not necessarily high.

3, Summary

Through this problem, we can understand the difference between the depth of the binary tree and the height of the binary tree. The depth is suitable for pre order traversal, and the height is suitable for post order traversal. The iterative method of this problem is actually a little complicated. You can have an idea, and you don't have to write it out.

But recursion must be mastered!

Tags: Algorithm data structure

Posted on Wed, 22 Sep 2021 11:11:30 -0400 by chimp1950