🧠
Iterative BFS with Queue and Max Tracking
💡 This approach uses breadth-first search to traverse the tree level by level, carrying the max value seen on the path to each node. It helps understand BFS traversal with state propagation.
Intuition
Use a queue to traverse nodes level by level. Along with each node, store the max value seen on the path from the root. Count nodes whose value is at least the max value.
Algorithm
- Initialize a queue with the root node and its value as the current max.
- While the queue is not empty, dequeue a node and its max value.
- If the node's value is greater or equal to the max, increment the count.
- Enqueue the children with updated max values.
💡 The key is to carry the max value along with each node in the queue to maintain correct state during BFS.
from collections import deque
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def count_good_nodes(root):
if not root:
return 0
count = 0
queue = deque([(root, root.val)])
while queue:
node, max_val = queue.popleft()
if node.val >= max_val:
count += 1
max_val = max(max_val, node.val)
if node.left:
queue.append((node.left, max_val))
if node.right:
queue.append((node.right, max_val))
return count
# Example usage:
if __name__ == '__main__':
root = TreeNode(3)
root.left = TreeNode(1, TreeNode(3))
root.right = TreeNode(4, TreeNode(1), TreeNode(5))
print(count_good_nodes(root)) # Output: 4
Line Notes
queue = deque([(root, root.val)])Initialize queue with root and its value as max_val
while queue:Process nodes level by level until queue is empty
node, max_val = queue.popleft()Extract current node and max_val for this path
if node.val >= max_val:Check if current node is a good node
import java.util.*;
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int val) { this.val = val; }
}
public class Solution {
public int countGoodNodes(TreeNode root) {
if (root == null) return 0;
int count = 0;
Queue<Pair<TreeNode, Integer>> queue = new LinkedList<>();
queue.offer(new Pair<>(root, root.val));
while (!queue.isEmpty()) {
Pair<TreeNode, Integer> p = queue.poll();
TreeNode node = p.getKey();
int maxVal = p.getValue();
if (node.val >= maxVal) count++;
maxVal = Math.max(maxVal, node.val);
if (node.left != null) queue.offer(new Pair<>(node.left, maxVal));
if (node.right != null) queue.offer(new Pair<>(node.right, maxVal));
}
return count;
}
public static void main(String[] args) {
TreeNode root = new TreeNode(3);
root.left = new TreeNode(1);
root.left.left = new TreeNode(3);
root.right = new TreeNode(4);
root.right.left = new TreeNode(1);
root.right.right = new TreeNode(5);
Solution sol = new Solution();
System.out.println(sol.countGoodNodes(root)); // Output: 4
}
}
// Note: Use javafx.util.Pair or define your own Pair class if javafx is unavailable.
Line Notes
Queue<Pair<TreeNode, Integer>> queue = new LinkedList<>();Queue stores nodes with their maxVal on path
queue.offer(new Pair<>(root, root.val));Start BFS with root and its value as maxVal
Pair<TreeNode, Integer> p = queue.poll();Dequeue node and maxVal for processing
if (node.val >= maxVal) count++;Count node if it is good
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
struct TreeNode {
int val;
TreeNode *left, *right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
class Solution {
public:
int countGoodNodes(TreeNode* root) {
if (!root) return 0;
int count = 0;
queue<pair<TreeNode*, int>> q;
q.push({root, root->val});
while (!q.empty()) {
auto [node, maxVal] = q.front(); q.pop();
if (node->val >= maxVal) count++;
maxVal = max(maxVal, node->val);
if (node->left) q.push({node->left, maxVal});
if (node->right) q.push({node->right, maxVal});
}
return count;
}
};
int main() {
TreeNode* root = new TreeNode(3);
root->left = new TreeNode(1);
root->left->left = new TreeNode(3);
root->right = new TreeNode(4);
root->right->left = new TreeNode(1);
root->right->right = new TreeNode(5);
Solution sol;
cout << sol.countGoodNodes(root) << endl; // Output: 4
return 0;
}
Line Notes
queue<pair<TreeNode*, int>> q;Queue holds nodes paired with maxVal on path
q.push({root, root->val});Initialize BFS with root node and its value
auto [node, maxVal] = q.front(); q.pop();Extract current node and maxVal
if (node->val >= maxVal) count++;Count node if it qualifies as good
class TreeNode {
constructor(val=0, left=null, right=null) {
this.val = val;
this.left = left;
this.right = right;
}
}
function countGoodNodes(root) {
if (!root) return 0;
let count = 0;
const queue = [[root, root.val]];
while (queue.length > 0) {
const [node, maxVal] = queue.shift();
if (node.val >= maxVal) count++;
const newMax = Math.max(maxVal, node.val);
if (node.left) queue.push([node.left, newMax]);
if (node.right) queue.push([node.right, newMax]);
}
return count;
}
// Example usage:
const root = new TreeNode(3,
new TreeNode(1, new TreeNode(3)),
new TreeNode(4, new TreeNode(1), new TreeNode(5))
);
console.log(countGoodNodes(root)); // Output: 4
Line Notes
const queue = [[root, root.val]];Initialize queue with root and its value as maxVal
while (queue.length > 0) {Process nodes until queue is empty
const [node, maxVal] = queue.shift();Dequeue node and maxVal for processing
if (node.val >= maxVal) count++;Count node if it is a good node
Each node is visited once. The queue can hold up to O(n) nodes in the worst case (e.g., a complete binary tree).
💡 For 100,000 nodes, this means 100,000 operations and potentially storing many nodes in the queue at once.
Interview Verdict: Accepted
This approach is equally efficient as recursion but uses explicit queue management, which some candidates prefer.