Balanced Binary Tree

🏠 ⬅️ ➡️

Given a binary tree, determine if it is height-balanced.

Example 1:

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

Example 2:

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

Example 3:

Input: root = [] Output: true

Constraints:

  • The number of nodes in the tree is in the range [0, 5000].
  • -104 <= Node.val <= 104

Note: This problem is from LeetCode.
Compiled
Executed
Correct
program main
    ! Solves the problem: Given a binary tree, determine if it is height-balanced.
    implicit none

    type :: node_t
        integer :: val
        type(node_t), pointer :: left => null(), right => null()
    end type

    type(node_t), target :: root

    call solve(root)

contains

    function is_height_balanced(root) result(is_balanced)
        ! Determines if the given binary tree is height-balanced.
        implicit none
        class(node_t), intent(in) :: root
        logical :: is_balanced
        integer :: depth

        is_balanced = .true.
        depth = 0
        call check_depth(root, depth, is_balanced)
    end function

    subroutine check_depth(root, depth, is_balanced)
        ! Recursive function to check the depth of the given binary tree.
        implicit none
        class(node_t), intent(in) :: root
        integer, intent(inout) :: depth
        logical, intent(inout) :: is_balanced

        if (associated(root%left)) then
            call check_depth(root%left, depth + 1, is_balanced)
        end if
        if (associated(root%right)) then
            call check_depth(root%right, depth + 1, is_balanced)
        end if

        if (abs(depth - get_depth(root%left)) > 1) then
            is_balanced = .false.
        end if
    end subroutine

    function get_depth(root) result(depth)
        ! Returns the depth of the given binary tree.
        implicit none
        class(node_t), intent(in) :: root
        integer :: depth

        if (.not. associated(root)) then
            depth = 0
        else
            depth = max(get_depth(root%left), get_depth(root%right)) + 1
        end if
    end function

    subroutine solve(root)
        ! Runs the solution on the given binary tree.
        implicit none
        type(node_t), intent(inout) :: root

        write (*, '(L1)') is_height_balanced(root)
    end subroutine
end program
Compiled
Executed
Correct
module height_balanced_binary_tree

implicit none

contains

function is_height_balanced(root) result(is_balanced)

    type(node), pointer, intent(in) :: root
    logical :: is_balanced

    is_balanced = is_height_balanced_recursive(root)

end function is_height_balanced

recursive function is_height_balanced_recursive(root) result(is_balanced)

    type(node), pointer, intent(in) :: root
    logical :: is_balanced

    integer :: height_left, height_right

    if (.not. associated(root)) then
        is_balanced = .true.
        return
    end if

    is_balanced = .false.

    height_left = height(root%left)
    height_right = height(root%right)

    if (abs(height_left - height_right) <= 1) then
        is_balanced = is_height_balanced_recursive(root%left) .and. &
                      is_height_balanced_recursive(root%right)
    end if

end function is_height_balanced_recursive

function height(root) result(height)

    type(node), pointer, intent(in) :: root
    integer :: height

    if (.not. associated(root)) then
        height = 0
        return
    end if

    height = max(height(root%left), height(root%right)) + 1

end function height

type node
    integer :: val
    type(node), pointer :: left
    type(node), pointer :: right
end type node

end module height_balanced_binary_tree

program test

use height_balanced_binary_tree
implicit none

type(node), pointer :: root

! Example 1
root = create_node(3)
root%left = create_node(9)
root%right = create_node(20)
root%left%left = create_node(15)
root%left%right = create_node(7)

if (is_height_balanced(root)) then
    write (*,*) "Example 1: Height-balanced"
else
    write (*,*) "Example 1: Not height-balanced"
end if

! Example 2
root = create_node(1)
root%left = create_node(2)
root%right = create_node(2)
root%left%left = create_node(3)
root%left%right = create_node(3)
root%right%left = create_node(4)
root%right%right = create_node(4)

if (is_height_balanced(root)) then
    write (*,*) "Example 2: Height-balanced"
else
    write (*,*) "Example 2: Not height-balanced"
end if

! Example 3
root = null()

if (is_height_balanced(root)) then
    write (*,*) "Example 3: Height-balanced"
else
    write (*,*) "Example 3: Not height-balanced"
end if

contains

function create_node(val) result(node)

    integer, intent(in) :: val
    type(node) :: node

    allocate(node)
    node%val = val
    node%left = null()
    node%right = null()

end function create_node

end program test
🌐 Data from online sources
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def getHeight(node):
    if not node:
        return 0
    left_height = getHeight(node.left)
    right_height = getHeight(node.right)
    if left_height == -1 or right_height == -1 or abs(left_height - right_height) > 1:
        return -1
    return 1 + max(left_height, right_height)

def isBalanced(root):
    return getHeight(root) != -1
The algorithm is based on the depth-first search. In this algorithm, we define a helper function named `getHeight` which will return the height of the given subtree if it is balanced, otherwise, it will return -1.

The getHeight function works as follows: 1. If the current node is null, return 0 (base case). 2. Call the function recursively for the left subtree (leftHeight) and the right subtree (rightHeight). 3. If either of the subtrees is not balanced or the height difference is greater than 1, return -1. 4. Otherwise, return the maximum height of the left and right subtrees incremented by 1.

The main function isBalanced just calls the getHeight function and checks whether its result is -1 or not. If it is not -1, the binary tree is height-balanced, otherwise, it is not balanced.

🌐 Data from online sources
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
};

int getHeight(TreeNode* node) {
    if (!node) return 0;
    int leftHeight = getHeight(node->left);
    int rightHeight = getHeight(node->right);
    if (leftHeight == -1 || rightHeight == -1 || abs(leftHeight - rightHeight) > 1)
        return -1;
    return 1 + max(leftHeight, rightHeight);
}

bool isBalanced(TreeNode* root) {
    return getHeight(root) != -1;
}
The algorithm is based on the depth-first search. In this algorithm, we define a helper function named `getHeight` which will return the height of the given subtree if it is balanced, otherwise, it will return -1.

The getHeight function works as follows: 1. If the current node is null, return 0 (base case). 2. Call the function recursively for the left subtree (leftHeight) and the right subtree (rightHeight). 3. If either of the subtrees is not balanced or the height difference is greater than 1, return -1. 4. Otherwise, return the maximum height of the left and right subtrees incremented by 1.

The main function isBalanced just calls the getHeight function and checks whether its result is -1 or not. If it is not -1, the binary tree is height-balanced, otherwise, it is not balanced.