Maximum Difference Between Node and Ancestor
Problem
Given the root of a binary tree, find the maximum value v for which there exist different nodes a and b where v = |a.val - b.val| and a is an ancestor of b.
A node a is an ancestor of b if either: any child of a is equal to b or any child of a is an ancestor of b.
Examples
Example 1:
graph TD H(8) H --- C(3) & J(10) C(3) --- A(1) C(3) --- F(6) F --- D(4) & G(7) J ~~~ N1:::hidden J --- N(14) N --- M(13) N ~~~ N2:::hidden classDef hidden display:none
Input: root = [8,3,10,1,6,null,14,null,null,4,7,13]
Output: 7
Explanation: We have various ancestor-node differences, some of which are given below :
|8 - 3| = 5
|3 - 7| = 4
|8 - 1| = 7
|10 - 13| = 3
Among all possible differences, the maximum value of 7 is obtained by |8 - 1| = 7.
Example 2:
graph TD A(1) A ~~~ N1:::hidden A --- B(2) B ~~~ N2:::hidden B --- F(0) F --- C(3) F ~~~ N3:::hidden classDef hidden display:none
Input: root = [1,null,2,null,0,3]
Output: 3
Solution
Method 1 - DFS
To solve this problem, we need to find the maximum difference between the values of a and b such that a is an ancestor of b in a binary tree. This essentially requires traversing the tree while keeping track of the minimum and maximum values encountered along the path from the root to each node. The difference between these values at any point will help in determining the desired v.
The main idea is a depth-first traversal (DFS), where we recursively explore the tree, updating the minimum and maximum values encountered so far.
Here is the approach:
- Start at the root and initialise the current minimum (
cur_min) and maximum (cur_max) to the root's value. - For each child node, update the current minimum and maximum based on the child's value, and compute the absolute difference between the node's value and the current minimum or maximum.
- Propagate the updated values down the tree.
- Keep track of the global maximum difference (
ans) using these values. - Base Case:
- If the node is
null, return immediately (there’s no further subtree to explore).
- If the node is
- Recursive Calculations:
- Calculate the max difference for the left and right subtrees.
- Add the returned values to the overall result.
Code
Java
class Solution {
public int maxAncestorDiff(TreeNode root) {
return dfs(root, root.val, root.val);
}
private int dfs(TreeNode node, int curMin, int curMax) {
if (node == null) {
return curMax - curMin;
}
curMin = Math.min(curMin, node.val);
curMax = Math.max(curMax, node.val);
int leftDiff = dfs(node.left, curMin, curMax);
int rightDiff = dfs(node.right, curMin, curMax);
return Math.max(leftDiff, rightDiff);
}
}
Python
class Solution:
def maxAncestorDiff(self, root: Optional[TreeNode]) -> int:
def dfs(node: Optional[TreeNode], cur_min: int, cur_max: int) -> int:
if not node:
return cur_max - cur_min
cur_min = min(cur_min, node.val)
cur_max = max(cur_max, node.val)
left_diff = dfs(node.left, cur_min, cur_max)
right_diff = dfs(node.right, cur_min, cur_max)
return max(left_diff, right_diff)
return dfs(root, root.val, root.val)
Complexity
- ⏰ Time complexity:
O(n). Each node is visited exactly once during the DFS traversal of the tree. - 🧺 Space complexity:
O(h). The recursion depth will be equal to the height of the binary tree (h). In the worst case,h = nfor a skewed tree.