Given the root of a binary tree, and two integer values p
and q
representing two distinct nodes in the tree, your task is to find the number of edges in the shortest path between the nodes with values p
and q
.
p
and q
exist in the tree.The output should be an integer representing the distance (in number of edges) between the two nodes.
At first glance, it might seem like you need to search from one node to the other, but since the tree is undirected (you can move up or down), the shortest path between two nodes always goes through their lowest common ancestor (LCA).
The brute-force idea would be to find the path from the root to p
and from the root to q
, then compare the paths to find where they diverge (their LCA). The sum of the unique edges from the LCA to each node gives the answer.
However, a more optimized approach is to:
p
and q
.p
and from the LCA to q
.Here's how to solve the problem step-by-step:
p
or q
, return the node.p
, counting edges.q
.p
and q
in a tree is always via their LCA.This approach is efficient, intuitive, and leverages the properties of trees.
Consider this tree:
1 / \ 2 3 / \ 4 5
Suppose p = 4
and q = 5
.
The shortest path between node 4 and node 5 is 2 edges: 4 - 2 - 5.
p
and q
takes O(N) time each, where N is the number of nodes.p
and q
is O(N) in the worst case, but usually much less.Both approaches are linear in the number of nodes, but the optimized approach is more memory-efficient.
# 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
class Solution:
def findDistance(self, root: TreeNode, p: int, q: int) -> int:
def lca(node):
if not node or node.val == p or node.val == q:
return node
left = lca(node.left)
right = lca(node.right)
if left and right:
return node
return left or right
def distance(node, target, d):
if not node:
return -1
if node.val == target:
return d
left = distance(node.left, target, d+1)
if left != -1:
return left
return distance(node.right, target, d+1)
ancestor = lca(root)
return distance(ancestor, p, 0) + distance(ancestor, q, 0)
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* lca(TreeNode* node, int p, int q) {
if (!node || node->val == p || node->val == q)
return node;
TreeNode* left = lca(node->left, p, q);
TreeNode* right = lca(node->right, p, q);
if (left && right) return node;
return left ? left : right;
}
int distance(TreeNode* node, int target, int d) {
if (!node) return -1;
if (node->val == target) return d;
int left = distance(node->left, target, d+1);
if (left != -1) return left;
return distance(node->right, target, d+1);
}
int findDistance(TreeNode* root, int p, int q) {
TreeNode* ancestor = lca(root, p, q);
return distance(ancestor, p, 0) + distance(ancestor, q, 0);
}
};
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
private TreeNode lca(TreeNode node, int p, int q) {
if (node == null || node.val == p || node.val == q)
return node;
TreeNode left = lca(node.left, p, q);
TreeNode right = lca(node.right, p, q);
if (left != null && right != null) return node;
return left != null ? left : right;
}
private int distance(TreeNode node, int target, int d) {
if (node == null) return -1;
if (node.val == target) return d;
int left = distance(node.left, target, d + 1);
if (left != -1) return left;
return distance(node.right, target, d + 1);
}
public int findDistance(TreeNode root, int p, int q) {
TreeNode ancestor = lca(root, p, q);
return distance(ancestor, p, 0) + distance(ancestor, q, 0);
}
}
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
var findDistance = function(root, p, q) {
function lca(node) {
if (!node || node.val === p || node.val === q) return node;
let left = lca(node.left);
let right = lca(node.right);
if (left && right) return node;
return left || right;
}
function distance(node, target, d) {
if (!node) return -1;
if (node.val === target) return d;
let left = distance(node.left, target, d+1);
if (left !== -1) return left;
return distance(node.right, target, d+1);
}
let ancestor = lca(root);
return distance(ancestor, p, 0) + distance(ancestor, q, 0);
};
To find the distance between two nodes in a binary tree, the most efficient strategy is to identify their lowest common ancestor (LCA) and sum the distances from the LCA to each node. This leverages tree properties and avoids unnecessary repeated traversals. The solution is elegant, intuitive, and runs in linear time with respect to the number of nodes, making it both practical and optimal for large trees.