530. Minimum Absolute Difference in BST
Problem¶
Given the root
of a Binary Search Tree (BST), return the minimum absolute difference between the values of any two different nodes in the tree.
Example 1:
Input: root = [4,2,6,1,3]
Output: 1
Example 2:
Input: root = [1,0,48,null,null,12,49]
Output: 1
Constraints:
- The number of nodes in the tree is in the range
[2, 104]
. 0 <= Node.val <= 105
Note: This question is the same as 783: https://leetcode.com/problems/minimum-distance-between-bst-nodes/
Solution¶
My sane approach¶
BTS is a searching Tree, and it cost O(log n) time to find any target value
I using a try and error, where with each node, I make an assumption that:
root
node is one of the two different nodes that we need to find togetMinimumDifference
- To get the minimum different node pair knowing
(root, <unknow>)
, - I will loop trough every node in the tree, find
class Solution: def getLargest(self, root): p = root while p.right: p = p.right return p def getSmallest(self, root): p = root while p.left: p = p.left return p def getValueDiff(self, x, y): return abs(x.val - y.val) def getMin(self, array): minValue = None for val in array: if val == None: continue if minValue == None: minValue = val if minValue > val: minValue = val return minValue def getMinimumDifference(self, root: Optional[TreeNode]) -> int: minDiff = None p = root if p.left: minLeftDiff = self.getValueDiff(p, self.getLargest(p.left)) minLeftChild = self.getMinimumDifference(p.left) minDiff = self.getMin([minDiff, minLeftDiff, minLeftChild]) if p.right: minRightDiff = self.getValueDiff(p, self.getSmallest(p.right)) minRightChild = self.getMinimumDifference(p.right) minDiff = self.getMin([minDiff, minRightDiff, minRightChild]) return minDiff
Overview¶
Given the root
of a Binary Search Tree (BST).
Our task is to return the minimum absolute difference between the values of any two different nodes in the tree.
Approach 1: Depth First Search¶
Intuition¶
Let’s try to solve a simpler problem first. Given a sorted array of integers, find the minimum difference between any two integers in the array. To solve this problem, we don’t need to check every pair of integers. Instead, checking the difference between every two consecutive integers would work. This is because the array is sorted. We will make use of this to solve our original problem.
In the original problem, we have some integer values (i.e. node values), and we need to find the minimum difference between any two values. Thus, the original problem is similar to the problem we discussed above if we keep those values in the sorted order.
To get all the node values we can use a graph traversal algorithm like depth-first search (DFS).
In DFS, we use a recursive function to explore nodes as far as possible along each branch. Upon reaching the end of a branch, we backtrack to the next branch and continue exploring.
Once we encounter an unvisited node, we will take one of its neighbor nodes (if exists) as the next node on this branch. Recursively call the function to take the next node as the ‘starting node’ and solve the subproblem.
If you are new to Depth First Search, please see our Leetcode Explore Card for more information on it!
After gathering all of the node values into a list of integers, we sort the list and compare the difference between every two consecutive integers to determine the minimum difference between the values.
Algorithm¶
- Create a list of integers
nodeValues
to store the node values. - Perform the DFS traversal over the given binary search tree. We call
dfs(root)
wheredfs
is a recursive method that takesTreeNode node
as a parameter. We perform the following in this method:- If
node
isnull
, return. - Add the current node’s value,
node.val
, in thenodeValues
list. - Recursively perform DFS from
node.left
. - Recursively perform DFS from
node.right
.
- If
- Sort the
nodeValues
list. - Create an integer variable
minDifference
and initialize it to infinity. - Iterate over
inorderNodes
starting from index1
, and for each element at indexi
, find the difference with the element at indexi - 1
and update the variableminDifference
accordingly. - Return
minDifference
.
Implementation¶
class Solution:
def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
nodeValues = []
def dfs(node):
if node is None:
return
nodeValues.append(node.val)
dfs(node.left)
dfs(node.right)
dfs(root)
nodeValues.sort()
minDifference = 1e9
for i in range(1, len(nodeValues)):
minDifference = min(minDifference, nodeValues[i] - nodeValues[i-1])
return minDifference
Complexity Analysis¶
Here, �n is the number of nodes in the given binary search tree.
-
Time complexity: O(n⋅logn)
- We traverse once over each node of the BST using DFS traversal which takes O(n) time.
- We take O(n⋅logn) time to sort a list of n elements.
- We iterate over the list of size n elements to find the minimum difference which also takes O(n) time.
-
Space complexity: O(n)
-
The DFS traversal is recursive and would take some space to store the stack calls. The maximum number of active stack calls at a time would be the tree’s height, which in the worst case would be O(n) when the tree is a straight line.
- We also need a list of size O(n) to store the values of all the nodes.
Approach 2: In-order Traversal Using List¶
Intuition¶
In the previous approach, we found all the values and then sorted them. This would work for any binary tree. However, we are given a binary search tree, which we didn’t take advantage of. A unique property of a binary search tree is that an inorder traversal handles the nodes in sorted order. This allows us to skip the sorting at the end.
The in-order traversal works by visiting the left subtree of a node first, then handling the node itself and finally visiting the right subtree. Since all the nodes in the left subtree are lesser than the current node’s value and all nodes in the right subtree are greater than the current node’s value, it generates a sorted list of values.
Here’s a visual representation of how inorder traversal works in a BST:
As you can see, we continue to move towards the left node until we no longer can, then handle the current node and repeat the process with the right node as the new starting node.
Algorithm¶
- Create a list of integers
inorderNodes
to store the node values. - Perform the inorder traversal of the binary search tree (BST). Call
inorderTraversal(root)
whereinorderTraversal
is a recursive method that takesTreeNode node
as a parameter. We perform the following in this method:- If
node
isnull
, return. - Recursively perform the in-order traversal for
node.left
. - Add the current node’s value,
node.val
, in theinorderNodes
list. - Recursively perform the in-order traversal for
node.right
.
- If
- Create an integer variable
minDifference
and initialize it to infinity. - Iterate over
inorderNodes
starting from index1
, and for each element at indexi
, find the difference with the element at indexi - 1
and update the variableminDifference
accordingly. - Return
minDifference
.
Implementation¶
class Solution:
def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
inorderNodes = []
def inorder(node):
if node is None:
return
inorder(node.left)
inorderNodes.append(node.val)
inorder(node.right)
inorder(root)
minDifference = 1e9
for i in range(1, len(inorderNodes)):
minDifference = min(minDifference, inorderNodes[i] - inorderNodes[i-1])
return minDifference
Complexity Analysis¶
Here, n is the number of nodes in the given binary search tree.
-
Time complexity: O(n)
- We traverse once over each node of the BST using in-order traversal which takes O(n) time.
- We iterate over the list of size n elements to find the minimum difference which also takes O(n) time.
-
Space complexity: O(n)
-
The in-order traversal is recursive and would take some space to store the stack calls. The maximum number of active stack calls at a time would be the tree’s height, which in the worst case would be O(n) when the tree is a straight line.
- We also need a list of size O(n) to store the values of all the nodes.
Approach 3: In-order Traversal Without List¶
Intuition¶
As we can notice in the previous approach, we only need the immediate in-order predecessor of any node to calculate the minimum difference. The rest of the nodes will not be needed and are stored unnecessarily in the list.
Thus, we can avoid storing elements in a list if we can find the difference between consecutive nodes on the fly during in-order traversal. For each node in the tree, we need the previous node we have handled, and then we can find the difference. This can be done using another variable prevNode
that will store the value of the node we handled previously in the in-order traversal. This way, we don’t have to store the elements in an array and at the same time, don’t have to re-iterate over the nodes again.
Algorithm¶
- Create an answer variable
minDifference
and initialize it to infinity. - Create a
TreeNode
variableprevNode
to keep track of the previous node we have traversed. Initialize it tonull
. - Perform the inorder traversal of the binary search tree (BST). Call
inorderTraversal(root)
whereinorderTraversal
is a recursive method that takesTreeNode node
as a parameter. We perform the following in this method:- If
node
isnull
, return. - Recursively perform the in-order traversal for
node.left
. - We handle
node
now. We check its difference with the previously visited nodeprevNode
. IfprevNode != null
, it means we have visited a node previously and hence, we try to updateminDifference
usingminDifference = min(minDifference, node.val - prevNode.val)
. - Recursively perform the in-order traversal for
node.right
.
- If
- Return
minDifference
.
Implementation¶
class Solution:
def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
self.minDistance = 1e9
# Initially, it will be null.
self.prevNode = None
def inorder(node):
if node is None:
return
inorder(node.left)
# Find the difference with the previous value if it is there.
if self.prevNode is not None:
self.minDistance = min(self.minDistance, node.val - self.prevNode)
self.prevNode = node.val
inorder(node.right)
inorder(root)
return self.minDistance
Complexity Analysis¶
Here, n is the number of nodes in the given binary search tree.
-
Time complexity: O(n)
- We traverse once over each node of the BST using in-order traversal which takes O(n) time.
-
Space complexity: O(n)
-
The in-order traversal is recursive and would take some space to store the stack calls. The maximum number of active stack calls at a time would be the tree’s height, which in the worst case would be O(n) when the tree is a straight line.
- Note that this space complexity is only for the worst-case scenario, and in the average case we have greatly improved our space complexity since we don’t need to create a list to store all the nodes.
Created : August 16, 2023