310. 最小高度树
思路:找到树中距离最长的两个点,最小高度的根一定在中点。
1) 任意选取一个点i,选取最远的作为下一次查找最远距离的点 j
2)从j出发 选取距离最远的 k , 最远距离则为 j - k 。
3)记录j -> k 的路径 ,再选取中点即可。ps:路过点数为偶则有两个
证明我也不太会写,离散好像讲过,记得好像有这么一回事。建议随便画一棵树任选一个节点 试试
class Solution {
static int idx ; // 节点索引
static int[] h; // 头节点
static int[] e; // 当前节点
static int[] ne; // 指向下一个节点
static int n;
public List<Integer> findMinHeightTrees(int n, int[][] edges) {
init(n);
for(int[] a : edges){
add(a[0],a[1]);
add(a[1],a[0]);
}
List<Integer> temp = new ArrayList<>();
List<Integer> ans = new ArrayList<>();
int max_0 = bfs(0);
int max_1 = bfs(max_0);
boolean vis[] = new boolean[n];
dfs(max_0,max_1,temp,vis);
int len = temp.size();
if(len % 2== 0) ans.add(temp.get(len/2-1));
ans.add(temp.get(len/2));
return ans;
}
// dfs 得到路径
public static boolean dfs(int idx,int tar,List<Integer> temp,boolean[] vis){
vis[idx] = true;
if(idx == tar){
temp.add(tar);
return true;
}
for(int i = h[idx] ; i != -1 ; i = ne[i]){
int j = e[i];
if(!vis[j] && dfs(j,tar,temp,vis)){
temp.add(idx);
return true;
}
}
return false;
}
// 这里使用邻接表存储的节点
public static void add(int a ,int b){
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
public static void init(int m){
n = 2*m;
h = new int[n];
e = new int[n];
ne = new int[n];
idx = 0;
Arrays.fill(h,-1);
}
// 直接用bfs 复杂度为n^2 大于10^8
// bfs 找原距离
public static int bfs(int idx ){
Deque<Integer> q = new LinkedList<>();
int[] step = new int[n];
Arrays.fill(step,-1);
step[idx] = 0;
int ans = 0;
q.add(idx);
int t = -1;
while(!q.isEmpty()){
t = q.poll();
for(int i = h[t] ; i != -1; i = ne[i]){
int j = e[i];
if(step[j] == -1){
q.add(j);
step[j] = step[t] + 1;
ans = Math.max(ans , step[j]);
}
}
}
return t;
}
}