Editorial
Core insight
Find Mode in Binary Search Tree · Tree Traversal Patterns (DFS & BFS)
Core Insight for Find Mode in Binary Search Tree
The key intuition is that in a sorted sequence, duplicate values are always adjacent. For example, if the tree contains three 2s, the inorder traversal will process them consecutively (e.g., ..., 1, 2, 2, 2, 3, ...).
We do not need a Hash Map to count frequencies globally. Instead, we only need to compare the current_node.val with the previous_node.val.
- Tracking State: We maintain a
current_countcounter. - Transition:
- If
current_node.val == previous_node.val, we incrementcurrent_count. - If
current_node.val != previous_node.val, we resetcurrent_countto 1.
- If
- Updating Modes: We maintain a
max_count.- If
current_count > max_count, we have found a new mode frequency. We clear our result list and start a new one with the current value. - If
current_count == max_count, the current value is another mode. We append it to the existing result list.
- If
Visual Description:
Imagine the recursion tree. The algorithm dives deep to the leftmost node (the smallest value). As the recursion unwinds and moves to right children, it traces the number line from left to right. Even though the structure is hierarchical, the visitation order is linear and sorted. We maintain a "pointer" to the previously visited value. If the traversal is at node 5 and the previous value was 5, we extend the streak. If the previous value was 4, the streak for 4 ends, and a new streak for 5 begins.
Deep dive
Full breakdown
Full reasoning, pitfalls, and implementation flow
LeetCode 501: Find Mode in Binary Search Tree Solution & Explanation
Problem Overview
TL;DR: By utilizing the sorted property of a Binary Search Tree (BST), we perform an inorder traversal to process nodes as a sorted sequence, allowing us to count frequencies and identify modes in a single pass without using a hash map.
The LeetCode 501 problem, "Find Mode in Binary Search Tree," asks us to identify the element(s) that appear most frequently in a BST. Unlike a standard binary tree, the BST structure guarantees a specific ordering of keys. If multiple elements share the same maximum frequency, we must return all of them. The solution should ideally handle the "Follow up" constraint: solving it without using extra space for frequency counting.
Brute Force Approach for Find Mode in Binary Search Tree
The most intuitive way to solve this problem is to treat the BST as a generic Binary Tree, ignoring its sorted property. We can traverse the entire tree and store the frequency of every element in a Hash Map.
Naive Algorithm Steps
- Initialize an empty Hash Map (or Dictionary) to store
value -> count. - Traverse the tree using any method (Preorder, Inorder, or Postorder).
- For every node visited, increment its count in the Hash Map.
- Iterate through the Hash Map to find the maximum frequency (
max_freq). - Iterate through the Hash Map again to collect all keys where
count == max_freq.
Pseudo-code
function findMode(root):
map = new HashMap()
function traverse(node):
if node is null return
map[node.val]++
traverse(node.left)
traverse(node.right)
traverse(root)
max_freq = 0
for count in map.values():
max_freq = max(max_freq, count)
result = []
for key in map.keys():
if map[key] == max_freq:
result.add(key)
return resultAnalysis
- Time Complexity: , where is the number of nodes. We visit every node once and iterate through the map.
- Space Complexity: . In the worst case (all unique values), the map stores entries.
- Why it fails: While this solution is correct, it fails to utilize the BST property. The problem includes a follow-up asking for extra space (excluding recursion stack). The brute force approach relies heavily on auxiliary space for the map, making it suboptimal for this specific constraint.
Algorithm Strategy: Tree DFS - Recursive Inorder Traversal
The strategy relies on a stateful Inorder Traversal. Since the recursion stack handles the traversal order, we manage the logic for frequency counting within the visitation step.
-
Global Variables (or Class Members):
prev: Stores the value of the previously visited node. Initialized to null/none.currCount: Tracks the frequency of the current value being processed.maxCount: Tracks the highest frequency seen so far.result: A list to store the mode(s).
-
Traversal Logic (DFS):
- Recursively call DFS on the left child.
- Process Node: Compare
root.valwithprev. UpdatecurrCount. ComparecurrCountwithmaxCountto updateresult. Updateprevtoroot.val. - Recursively call DFS on the right child.
-
Handling Updates:
- Crucially, when
currCountexceedsmaxCount, theresultlist is cleared because all previously stored modes are no longer the most frequent. The current value becomes the sole new mode.
- Crucially, when
Execution Flow
- Initialization: Set
maxCount = 0,currCount = 0,prev = null, andresult = []. - Start Recursion: Call
inorder(root). - Navigate Left: The function recurses until it hits the leftmost leaf (smallest value).
- Process Node (e.g., Value A):
- Check
prev. Ifprevisnullorprev != A, resetcurrCount = 1. - If
prev == A, incrementcurrCount. - Mode Check:
- Is
currCount > maxCount? UpdatemaxCount = currCount. Clearresult. AddA. - Is
currCount == maxCount? AddAtoresult.
- Is
- Update
prev = A.
- Check
- Navigate Right: Recurse to the right child.
- Repeat: This continues for all nodes. The
prevvariable acts as the bridge between recursive calls, ensuring we treat the tree as a continuous sorted stream. - Return: Finally, return
result.
Proof of Correctness
The correctness hinges on the property of BSTs: Inorder Traversal produces a sorted sequence.
- Completeness: The traversal visits every node exactly once.
- Adjacency: Since the sequence is sorted, all instances of a value appear consecutively. We will never encounter an , then a , and then another .
- Counting: By resetting the counter whenever the value changes,
currCountaccurately reflects the total frequency of the contiguous block of identical values. - Maximization: By dynamically updating
resultwhenevercurrCountmatches or exceedsmaxCount, the algorithm guarantees that after the final node is processed,resultcontains exactly those elements with the global maximum frequency.
Pattern Reuse Notes
The Tree DFS - Recursive Inorder Traversal pattern is fundamental for Binary Search Trees. It allows us to process the tree as a sorted array.
- LeetCode 94: Binary Tree Inorder Traversal: The base pattern itself.
- LeetCode 98: Validate Binary Search Tree: Uses inorder traversal to verify that the sequence is strictly increasing (
prev < current). - LeetCode 173: Binary Search Tree Iterator: Implements a controlled inorder traversal using an explicit stack.
- LeetCode 230: Kth Smallest Element in a BST: Stops the inorder traversal early once the -th element is reached.
Feynman coach · Before you peek at the code
Can you explain the core insight in your own words?
If you can explain it before reading code, you’re far more likely to recall it under interview pressure.
Reference Implementation
C++ Solution for LeetCode 501
1class Solution {
2private:
3 int maxCount = 0;
4 int currCount = 0;
5 TreeNode* prev = nullptr;
6 vector<int> result;
7
8 void inorder(TreeNode* node) {
9 if (!node) return;
10
11 // 1. Traverse Left
12 inorder(node->left);
13
14 // 2. Process Current Node
15 if (prev && prev->val == node->val) {
16 currCount++;
17 } else {
18 currCount = 1;
19 }
20
21 if (currCount > maxCount) {
22 maxCount = currCount;
23 result.clear();
24 result.push_back(node->val);
25 } else if (currCount == maxCount) {
26 result.push_back(node->val);
27 }
28
29 prev = node;
30
31 // 3. Traverse Right
32 inorder(node->right);
33 }
34
35public:
36 vector<int> findMode(TreeNode* root) {
37 inorder(root);
38 return result;
39 }
40};Java Solution for LeetCode 501
1class Solution {
2 private Integer prev = null;
3 private int currCount = 0;
4 private int maxCount = 0;
5 private List<Integer> result;
6
7 public int[] findMode(TreeNode root) {
8 result = new ArrayList<>();
9 inorder(root);
10
11 // Convert List to int[]
12 int[] modes = new int[result.size()];
13 for (int i = 0; i < result.size(); i++) {
14 modes[i] = result.get(i);
15 }
16 return modes;
17 }
18
19 private void inorder(TreeNode node) {
20 if (node == null) return;
21
22 // 1. Traverse Left
23 inorder(node.left);
24
25 // 2. Process Current Node
26 if (prev != null && prev == node.val) {
27 currCount++;
28 } else {
29 currCount = 1;
30 }
31
32 if (currCount > maxCount) {
33 maxCount = currCount;
34 result.clear();
35 result.add(node.val);
36 } else if (currCount == maxCount) {
37 result.add(node.val);
38 }
39
40 prev = node.val;
41
42 // 3. Traverse Right
43 inorder(node.right);
44 }
45}Python Solution for LeetCode 501
1class Solution:
2 def findMode(self, root: Optional[TreeNode]) -> List[int]:
3 self.max_count = 0
4 self.curr_count = 0
5 self.prev_val = None
6 self.result = []
7
8 def inorder(node):
9 if not node:
10 return
11
12 # 1. Traverse Left
13 inorder(node.left)
14
15 # 2. Process Current Node
16 if node.val == self.prev_val:
17 self.curr_count += 1
18 else:
19 self.curr_count = 1
20
21 if self.curr_count > self.max_count:
22 self.max_count = self.curr_count
23 self.result = [node.val] # Clear and add
24 elif self.curr_count == self.max_count:
25 self.result.append(node.val)
26
27 self.prev_val = node.val
28
29 # 3. Traverse Right
30 inorder(node.right)
31
32 inorder(root)
33 return self.result