Grokking Tree Coding Patterns for Interviews
Ask Author
Back to course home

0% completed

Vote For New Content
Solution: Count Good Nodes in Binary Tree
Table of Contents

Contents are not accessible

Contents are not accessible

Contents are not accessible

Contents are not accessible

Contents are not accessible

Problem Statement

Given a binary tree root, return the number of good nodes in the binary tree.

A node is considered good if in the path from the root to this node, there are no nodes with a value greater than this node's value.

Examples

Example 1

  • Input: root = [3, 1, 3, 3, null, 1, 5]
Image
  • Expected Output: 4
  • Explanation:
    • Root node (3) is always good.
    • Node 5 is also a good node.
    • Both nodes 3 are good.

Example 2

  • Input: root = [2, 3, 4, 1, null, null, 5]
Image
  • Expected Output: 4
  • Explanation:
    • Nodes 2, 3, 4, and 5 are good.
    • The node with value 1 is not good because 3 is greater and comes before it.

Example 3

  • Input: root = [10, 8, 15, 7, 9, 12, 20]
Image
  • Expected Output: 3
  • Explanation:
    • Nodes 10, 15, and 20 are good.

Constraints:

  • The number of nodes in the binary tree is in the range [1, 10^<sup>5</sup>].
  • Each node's value is between [-10<sup>4</sup>, 10^<sup>4</sup>].

Solution

To solve this problem, we will use Depth-First Search (DFS) traversal. The idea is to traverse the tree starting from the root and keep track of the maximum value encountered on the path from the root to the current node. If the current node's value is greater than or equal to the maximum value seen so far, it is a good node. We then update the maximum value and continue to traverse the tree.

This approach works because it ensures that we only count a node as good if all nodes on the path from the root to that node have values less than or equal to the current node's value. By updating the maximum value dynamically as we traverse, we can efficiently determine if a node is good.

Step-by-step Algorithm

  1. Initialization:

    • Start with the root node of the tree.
  2. Define Helper Function (DFS):

    • Define a helper function dfs(node, maxVal) to perform depth-first search (DFS) on the tree. Initially, consider root node's value as a maxVal.
    • If the current node is null, return 0 because there are no nodes to consider.
  3. Check Good Node:

    • Check if the value of the current node is greater than or equal to maxVal.
    • If it is, this node is a good node. Initialize a variable count to 1.
    • Otherwise, set count to 0.
  4. Update Maximum Value:

    • Update maxVal to be the maximum of the current node's value and the previous maxVal.
  5. Recur for Subtrees:

    • Recursively call dfs for the left child of the current node with the updated maxVal and add the result to count.
    • Recursively call dfs for the right child of the current node with the updated maxVal and add the result to count.
  6. Return Count:

    • Return the total count of good nodes found in the current subtree.

Algorithm Walkthrough

Image
  1. Initialization:

    • Start at the root node with value 2.
    • Initialize maxVal = 2.
  2. Step-by-Step DFS Traversal:

    • At Node 2:

      • maxVal = 2
      • 2 >= 2, so node 2 is a good node.
      • Count = 1
      • Update maxVal = max(2, 2) = 2
      • Recur for left child (Node 3).
    • At Node 3:

      • maxVal = 2
      • 3 >= 2, so node 3 is a good node.
      • Count = 1
      • Update maxVal = max(2, 3) = 3
      • Recur for left child (Node 1).
    • At Node 1:

      • maxVal = 3

      • 1 < 3, so node 1 is not a good node.

      • Count = 0

      • maxVal remains 3

      • Recur for left and right children (both are null), so return 0 for both.

      • Total count from Node 1's subtree: 0

    • Back at Node 3:

      • Count from left subtree (Node 1) = 0
      • Recur for right child (null), so return 0.
      • Total count from Node 3's subtree: 1 (Node 3 itself)
    • Back at Node 2:

      • Count from left subtree (Node 3) = 1
      • Recur for right child (Node 4).
    • At Node 4:

      • maxVal = 2
      • 4 >= 2, so node 4 is a good node.
      • Count = 1
      • Update maxVal = max(2, 4) = 4
      • Recur for left child (null), so return 0.
      • Recur for right child (Node 5).
    • At Node 5:

      • maxVal = 4

      • 5 >= 4, so node 5 is a good node.

      • Count = 1

      • Update maxVal = max(4, 5) = 5

      • Recur for left and right children (both are null), so return 0 for both.

      • Total count from Node 5's subtree: 1

    • Back at Node 4:

      • Count from right subtree (Node 5) = 1
      • Total count from Node 4's subtree: 2 (Nodes 4 and 5)
    • Back at Node 2:

      • Count from right subtree (Node 4) = 2
      • Total count from Node 2's subtree: 4 (Nodes 2, 3, 4, 5)
  3. Final Count:

    • The total count of good nodes in the tree is 4.

Code

Python3
Python3

. . . .

Complexity Analysis

Time Complexity

The time complexity of this algorithm is O(N), where N is the number of nodes in the tree. This is because we visit each node exactly once during the DFS traversal.

Space Complexity

The space complexity is O(H), where H is the height of the tree. This is due to the recursion stack used during the DFS traversal. In the worst case (for a skewed tree), H can be as large as N, leading to a space complexity of O(N). For a balanced tree, the space complexity would be O(log N).

.....

.....

.....

Like the course? Get enrolled and start learning!

Table of Contents

Contents are not accessible

Contents are not accessible

Contents are not accessible

Contents are not accessible

Contents are not accessible