A clear explanation of finding the minimum difference between two BST node values using inorder traversal.
Problem Restatement
We are given the root of a Binary Search Tree.
We need to return the minimum absolute difference between the values of any two different nodes in the tree.
The important property is that the tree is a BST. For every node:
left subtree values < node value < right subtree valuesBecause of this property, an inorder traversal visits the node values in sorted order.
The problem guarantees that the tree has at least two nodes. The node values are non-negative.
Input and Output
| Item | Meaning |
|---|---|
| Input | The root of a Binary Search Tree |
| Output | The minimum absolute difference between any two node values |
| Node count | At least 2 nodes |
| Node values | Non-negative integers |
Function shape:
def getMinimumDifference(root: Optional[TreeNode]) -> int:
...Examples
Consider this BST:
4
/ \
2 6
/ \
1 3The inorder traversal gives:
[1, 2, 3, 4, 6]Now compare adjacent values:
2 - 1 = 1
3 - 2 = 1
4 - 3 = 1
6 - 4 = 2The minimum difference is:
1So the answer is:
1Another example:
1
\
48
/ \
12 49The inorder traversal gives:
[1, 12, 48, 49]Adjacent differences are:
12 - 1 = 11
48 - 12 = 36
49 - 48 = 1The minimum difference is:
1First Thought: Compare Every Pair
A direct solution is to collect all node values, then compare every pair.
For each pair of values a and b, compute:
abs(a - b)Then keep the smallest value.
This works, but it ignores the BST property.
If there are n nodes, comparing every pair takes:
O(n^2)We can do better.
Key Insight
In a sorted list, the minimum absolute difference must appear between two adjacent elements.
For example:
[1, 2, 3, 4, 6]The closest pair cannot be 1 and 4, because values between them, such as 2 and 3, are even closer candidates.
So after sorting, we only need to compare neighbors.
A BST gives sorted values for free through inorder traversal:
left -> node -> rightTherefore, we can traverse the BST in inorder order and compare each node value with the previously visited value.
Algorithm
Use inorder traversal.
Maintain two variables:
prev
answerprev stores the value of the previously visited node in inorder order.
answer stores the smallest difference seen so far.
During traversal:
- Visit the left subtree.
- Process the current node.
- Compare
node.valwithprev, ifprevexists. - Update
answer. - Set
prev = node.val. - Visit the right subtree.
At the end, return answer.
Correctness
Inorder traversal of a BST visits values in increasing order.
So the traversal produces the same order as sorting all node values.
In any sorted sequence, the minimum absolute difference between two values occurs between adjacent values. If two values are not adjacent, then at least one value lies between them, and one of the smaller gaps around that middle value is no larger than the larger outer gap.
The algorithm compares each value with the value immediately before it in inorder order. Therefore, it checks every adjacent pair in the sorted sequence.
Since the minimum difference must be among these adjacent pairs, the algorithm finds the correct minimum absolute difference.
Complexity
Let n be the number of nodes and h be the height of the tree.
| Metric | Value | Why |
|---|---|---|
| Time | O(n) | Each node is visited once |
| Space | O(h) | Recursion stack height is the tree height |
In the worst case, a skewed tree has height n, so the space can be O(n).
For a balanced tree, the space is O(log n).
Implementation
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
from typing import Optional
class Solution:
def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
prev = None
answer = float("inf")
def inorder(node: Optional[TreeNode]) -> None:
nonlocal prev, answer
if node is None:
return
inorder(node.left)
if prev is not None:
answer = min(answer, node.val - prev)
prev = node.val
inorder(node.right)
inorder(root)
return answerCode Explanation
We initialize:
prev = None
answer = float("inf")prev starts as None because there is no previous node before the first node in inorder traversal.
answer starts as infinity so that the first valid difference will replace it.
The traversal function is:
def inorder(node: Optional[TreeNode]) -> None:If the node is missing, we stop:
if node is None:
returnThen we visit the left subtree:
inorder(node.left)At this point, all smaller values have already been processed.
Now we process the current node. If there is a previous value, we compare:
answer = min(answer, node.val - prev)We do not need abs here because inorder traversal gives increasing values, so node.val >= prev.
Then we update:
prev = node.valFinally, we visit the right subtree:
inorder(node.right)This continues the sorted traversal.
Iterative Version
The same idea can be implemented with an explicit stack.
from typing import Optional
class Solution:
def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
stack = []
node = root
prev = None
answer = float("inf")
while stack or node:
while node:
stack.append(node)
node = node.left
node = stack.pop()
if prev is not None:
answer = min(answer, node.val - prev)
prev = node.val
node = node.right
return answerThis avoids recursive function calls, but the logic is the same.
Testing
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def run_tests():
s = Solution()
root = TreeNode(
4,
TreeNode(2, TreeNode(1), TreeNode(3)),
TreeNode(6),
)
assert s.getMinimumDifference(root) == 1
root = TreeNode(
1,
None,
TreeNode(48, TreeNode(12), TreeNode(49)),
)
assert s.getMinimumDifference(root) == 1
root = TreeNode(2, TreeNode(1), None)
assert s.getMinimumDifference(root) == 1
root = TreeNode(10, TreeNode(5), TreeNode(20))
assert s.getMinimumDifference(root) == 5
print("all tests passed")
run_tests()| Test | Why |
|---|---|
[4,2,6,1,3] | Standard balanced-ish BST example |
[1,null,48,null,null,12,49] | Checks a right-heavy shape |
| Two nodes | Minimum valid tree size |
| Wider gap values | Confirms the minimum is computed from sorted neighbors |