🧠
Brute Force (Calculate Height for Each Node as Root)
💡 This approach exists to build intuition by directly simulating the problem definition, even though it is inefficient. It helps understand what 'minimum height' means by explicitly computing heights.
Intuition
For each node, treat it as the root and compute the height of the tree by BFS or DFS. The nodes with the smallest height are the answer.
Algorithm
- For each node from 0 to n-1:
- Perform BFS/DFS to find the height of the tree rooted at that node.
- Track the minimum height found and the nodes that achieve it.
- Return all nodes with the minimum height.
💡 The main challenge is that computing height for each root requires traversing the entire tree repeatedly, which is expensive.
from collections import deque
def findMinHeightTrees(n, edges):
if n == 1:
return [0]
graph = [[] for _ in range(n)]
for u, v in edges:
graph[u].append(v)
graph[v].append(u)
def bfs(root):
visited = [False] * n
queue = deque([(root, 0)])
visited[root] = True
max_depth = 0
while queue:
node, depth = queue.popleft()
max_depth = max(max_depth, depth)
for nei in graph[node]:
if not visited[nei]:
visited[nei] = True
queue.append((nei, depth + 1))
return max_depth
min_height = float('inf')
res = []
for i in range(n):
height = bfs(i)
if height < min_height:
min_height = height
res = [i]
elif height == min_height:
res.append(i)
return res
# Driver code
if __name__ == '__main__':
print(findMinHeightTrees(4, [[1,0],[1,2],[1,3]])) # Output: [1]
Line Notes
if n == 1:Handle trivial single-node tree quickly
graph = [[] for _ in range(n)]Build adjacency list for efficient neighbor lookup
def bfs(root):Define BFS to compute height from a given root
queue = deque([(root, 0)])Initialize queue with root node and depth 0
max_depth = max(max_depth, depth)Track maximum depth reached during BFS
for i in range(n):Try each node as root to find minimum height
height = bfs(i)Compute height for current root candidate
if height < min_height:Update minimum height and result list accordingly
import java.util.*;
public class Solution {
public List<Integer> findMinHeightTrees(int n, int[][] edges) {
if (n == 1) return Collections.singletonList(0);
List<List<Integer>> graph = new ArrayList<>();
for (int i = 0; i < n; i++) graph.add(new ArrayList<>());
for (int[] edge : edges) {
graph.get(edge[0]).add(edge[1]);
graph.get(edge[1]).add(edge[0]);
}
int minHeight = Integer.MAX_VALUE;
List<Integer> res = new ArrayList<>();
for (int i = 0; i < n; i++) {
int height = bfs(i, graph, n);
if (height < minHeight) {
minHeight = height;
res.clear();
res.add(i);
} else if (height == minHeight) {
res.add(i);
}
}
return res;
}
private int bfs(int root, List<List<Integer>> graph, int n) {
boolean[] visited = new boolean[n];
Queue<int[]> queue = new LinkedList<>();
queue.offer(new int[]{root, 0});
visited[root] = true;
int maxDepth = 0;
while (!queue.isEmpty()) {
int[] curr = queue.poll();
int node = curr[0], depth = curr[1];
maxDepth = Math.max(maxDepth, depth);
for (int nei : graph.get(node)) {
if (!visited[nei]) {
visited[nei] = true;
queue.offer(new int[]{nei, depth + 1});
}
}
}
return maxDepth;
}
// Driver code
public static void main(String[] args) {
Solution sol = new Solution();
System.out.println(sol.findMinHeightTrees(4, new int[][]{{1,0},{1,2},{1,3}})); // [1]
}
}
Line Notes
if (n == 1) return Collections.singletonList(0);Quickly handle single node tree
List<List<Integer>> graph = new ArrayList<>();Create adjacency list for graph
for (int i = 0; i < n; i++) graph.add(new ArrayList<>());Initialize adjacency lists for each node
queue.offer(new int[]{root, 0});Start BFS from root with depth 0
maxDepth = Math.max(maxDepth, depth);Keep track of max depth during BFS
for (int i = 0; i < n; i++) {Try each node as root to find minimal height
if (height < minHeight) {Update minimum height and result list
#include <iostream>
#include <vector>
#include <queue>
#include <climits>
using namespace std;
class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
if (n == 1) return {0};
vector<vector<int>> graph(n);
for (auto& e : edges) {
graph[e[0]].push_back(e[1]);
graph[e[1]].push_back(e[0]);
}
int minHeight = INT_MAX;
vector<int> res;
for (int i = 0; i < n; i++) {
int height = bfs(i, graph, n);
if (height < minHeight) {
minHeight = height;
res.clear();
res.push_back(i);
} else if (height == minHeight) {
res.push_back(i);
}
}
return res;
}
private:
int bfs(int root, vector<vector<int>>& graph, int n) {
vector<bool> visited(n, false);
queue<pair<int,int>> q;
q.push({root, 0});
visited[root] = true;
int maxDepth = 0;
while (!q.empty()) {
auto [node, depth] = q.front(); q.pop();
maxDepth = max(maxDepth, depth);
for (int nei : graph[node]) {
if (!visited[nei]) {
visited[nei] = true;
q.push({nei, depth + 1});
}
}
}
return maxDepth;
}
};
// Driver code
int main() {
Solution sol;
vector<vector<int>> edges = {{1,0},{1,2},{1,3}};
vector<int> res = sol.findMinHeightTrees(4, edges);
for (int r : res) cout << r << ' '; // Output: 1
cout << endl;
return 0;
}
Line Notes
if (n == 1) return {0};Handle trivial single-node tree quickly
vector<vector<int>> graph(n);Build adjacency list for efficient neighbor lookup
q.push({root, 0});Initialize BFS queue with root and depth 0
maxDepth = max(maxDepth, depth);Track maximum depth reached during BFS
for (int i = 0; i < n; i++) {Try each node as root to find minimum height
int height = bfs(i, graph, n);Compute height for current root candidate
if (height < minHeight) {Update minimum height and result list accordingly
function findMinHeightTrees(n, edges) {
if (n === 1) return [0];
const graph = Array.from({length: n}, () => []);
for (const [u, v] of edges) {
graph[u].push(v);
graph[v].push(u);
}
function bfs(root) {
const visited = new Array(n).fill(false);
const queue = [[root, 0]];
visited[root] = true;
let maxDepth = 0;
while (queue.length > 0) {
const [node, depth] = queue.shift();
maxDepth = Math.max(maxDepth, depth);
for (const nei of graph[node]) {
if (!visited[nei]) {
visited[nei] = true;
queue.push([nei, depth + 1]);
}
}
}
return maxDepth;
}
let minHeight = Infinity;
const res = [];
for (let i = 0; i < n; i++) {
const height = bfs(i);
if (height < minHeight) {
minHeight = height;
res.length = 0;
res.push(i);
} else if (height === minHeight) {
res.push(i);
}
}
return res;
}
// Driver code
console.log(findMinHeightTrees(4, [[1,0],[1,2],[1,3]])); // Output: [1]
Line Notes
if (n === 1) return [0];Handle single node tree quickly
const graph = Array.from({length: n}, () => []);Build adjacency list for graph
const queue = [[root, 0]];Initialize BFS queue with root and depth 0
maxDepth = Math.max(maxDepth, depth);Track maximum depth during BFS
for (let i = 0; i < n; i++) {Try each node as root to find minimal height
const height = bfs(i);Compute height for current root candidate
if (height < minHeight) {Update minimum height and result list
TimeO(n^2) because for each node we do a BFS/DFS that takes O(n) time
SpaceO(n) for adjacency list and BFS queue
We run BFS from each node, each BFS takes O(n), repeated n times leads to O(n^2).
💡 For n=20, this means roughly 400 BFS traversals, which is manageable but grows quickly and becomes impractical for large n.
Interview Verdict: TLE for large inputs
This approach is too slow for large trees but is useful to understand the problem and correctness before optimizing.