Given a non-empty special binary tree consisting of nodes with the non-negative value, where each node in this tree has exactly two
or zero
sub-node. If the node has two sub-nodes, then this node's value is the smaller value among its two sub-nodes. More formally, the property root.val = min(root.left.val, root.right.val)
always holds.
Given such a binary tree, you need to output the second minimum value in the set made of all the nodes' value in the whole tree.
If no such second minimum value exists, output -1 instead.
Example 1:
Input: root = [2,2,5,null,null,5,7] Output: 5 Explanation: The smallest value is 2, the second smallest value is 5.
Example 2:
Input: root = [2,2,2] Output: -1 Explanation: The smallest value is 2, but there isn't any second smallest value.
Constraints:
[1, 25]
.1 <= Node.val <= 231 - 1
root.val == min(root.left.val, root.right.val)
for each internal node of the tree.This problem asks to find the second minimum value in a special binary tree. The special property of this tree is that each node's value is the minimum of its children's values. This property significantly simplifies the search for the second minimum.
The solution uses Depth-First Search (DFS) to traverse the tree. The algorithm maintains two variables:
ans
: Stores the current second minimum value found. Initialized to -1, indicating no second minimum found yet.v
: Stores the minimum value in the tree (the root's value). We know this because of the tree's special property.The dfs
function recursively visits each node. If a node's value (root.val
) is greater than the minimum value (v
), it means we've found a candidate for the second minimum. We update ans
accordingly, choosing the smaller value between the current ans
and the node's value.
Time Complexity Analysis:
The DFS algorithm visits each node in the tree exactly once. Therefore, the time complexity is O(N), where N is the number of nodes in the tree.
Space Complexity Analysis:
The space complexity depends on the recursion depth. In the worst case (a skewed tree), the depth is O(N). In the best case (a balanced tree), the depth is O(log N). Thus, the space complexity is O(N) in the worst case and O(log N) in the best case. However, we can also consider the space used by the recursive call stack as part of the space complexity, leading to O(H) where H is the height of the tree.
class Solution:
def findSecondMinimumValue(self, root: Optional[TreeNode]) -> int:
def dfs(root):
if root:
dfs(root.left)
dfs(root.right)
nonlocal ans, v # access variables from the outer scope
if root.val > v:
ans = root.val if ans == -1 else min(ans, root.val)
ans, v = -1, root.val # Initialize ans and v
dfs(root)
return ans
The Python code efficiently implements the described algorithm. The nonlocal
keyword is crucial; it allows the inner dfs
function to modify the ans
and v
variables from the outer scope. The conditional assignment ans = root.val if ans == -1 else min(ans, root.val)
concisely handles the case where ans
is initially -1.
The other languages (Java, C++, Go, JavaScript) follow the same logic, adapting the syntax to their respective language features. Note that the nonlocal
keyword is not needed in these languages because variable scope is handled differently. In Java, C++, and Go, the ans
variable is declared and updated within the dfs
function, but it's a member variable of the Solution class. In JavaScript, ans
is declared in the outer scope and accessed in the inner function without special keywords.
In all examples, the initial value of ans
is set to -1, indicating no second minimum initially. The algorithm then recursively traverses the tree, updating ans
whenever a node with a value greater than the minimum (v
) is encountered. The final ans
value represents the second minimum value in the tree or -1 if no such value exists.