You are given the root
of a binary tree and an integer distance
. A pair of two different leaf nodes of a binary tree is said to be good if the length of the shortest path between them is less than or equal to distance
.
Return the number of good leaf node pairs in the tree.
Example 1:
Input: root = [1,2,3,null,4], distance = 3 Output: 1 Explanation: The leaf nodes of the tree are 3 and 4 and the length of the shortest path between them is 3. This is the only good pair.
Example 2:
Input: root = [1,2,3,4,5,6,7], distance = 3 Output: 2 Explanation: The good pairs are [4,5] and [6,7] with shortest path = 2. The pair [4,6] is not good because the length of ther shortest path between them is 4.
Example 3:
Input: root = [7,1,4,6,null,5,3,null,null,null,null,null,2], distance = 3 Output: 1 Explanation: The only good pair is [2,5].
Constraints:
tree
is in the range [1, 210].
1 <= Node.val <= 100
1 <= distance <= 10
The problem asks to find the number of good leaf node pairs in a given binary tree. A good pair is defined as a pair of distinct leaf nodes where the shortest path between them is less than or equal to a given distance distance
.
The solution uses a depth-first search (DFS) approach to traverse the binary tree. The key idea is to count the number of leaf nodes at each depth for the left and right subtrees separately. Then, we iterate through the leaf node counts at different depths and calculate the number of good pairs based on the condition that the sum of their depths should be less than or equal to the given distance
.
The Python code below implements this approach:
from collections import Counter
# 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 countPairs(self, root: TreeNode, distance: int) -> int:
def dfs(node, depth, counts):
if not node:
return
if not node.left and not node.right: # Leaf node
counts[depth] += 1
return
dfs(node.left, depth + 1, counts)
dfs(node.right, depth + 1, counts)
count_left = Counter()
count_right = Counter()
dfs(root.left, 1, count_left) #depth starts from 1
dfs(root.right, 1, count_right)
ans = 0
for d1 in count_left:
for d2 in count_right:
if d1 + d2 <= distance:
ans += count_left[d1] * count_right[d2]
return ans + self.countPairs(root.left,distance) + self.countPairs(root.right,distance)
Explanation:
TreeNode
class: A simple definition for a tree node.
countPairs(root, distance)
: This is the main function. It recursively calls itself on the left and right subtrees to count pairs within those subtrees. It then focuses on pairs spanning the left and right subtrees of the current node.
dfs(node, depth, counts)
: This is a helper function that performs a depth-first search. It takes the current node, the current depth, and a Counter
object to store the counts of leaf nodes at each depth. If a leaf node is encountered, it increments the count for that depth.
Counting pairs: After the DFS calls for left and right subtrees, it iterates through the Counter
objects (count_left
and count_right
). For each pair of depths (d1, d2), if their sum is less than or equal to distance
, it adds the product of the counts at those depths to the total count (ans
). This accounts for all pairs of leaf nodes spanning across the left and right subtrees.
Recursive calls: Finally, the function recursively calls itself on the left and right subtrees to handle pairs within those subtrees.
Time Complexity: O(N), where N is the number of nodes in the tree. This is because the DFS visits each node once.
Space Complexity: O(H), where H is the height of the tree. This is due to the recursive call stack and the space used by the Counter
objects, which store counts for at most H depths. In the worst case (a skewed tree), H can be equal to N.
The code is provided in Python, Java, C++, Go, Typescript, and Javascript, all implementing the same core logic, with minor syntax adjustments for each language. The complexity analysis remains the same across all languages.