- 从各个点dfs,求出最小的高度
- memo的key和两者有关,一个是dfs的起点,一个是dfs的根结点,如下图
DFS
class Solution {
public:
// 对于每个点k,开一个单链表,存储k所有可以走到的点。h[k]存储这个单链表的头结点
int h[20005]; //邻接表存储树,有n个节点,所以需要n个队列头节点
int e[20005]; //存储元素
int ne[20005]; //存储列表的next值
int idx; //单链表指针
int n; //题目所给的输入,n个节点
vector<int> ans ={20005};
bool st[20005]; //记录节点是否被访问过,访问过则标记为true
unordered_map<int, int> memo;
// 添加一条边a->b
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
int dfs(int u, int root)
{
int key = u*1e5+root;
if(memo.count(key)) return memo[key];
int res = INT_MIN; //
st[u] = true; //标记访问过u节点
//访问u的每个子节点
for (int i = h[u]; i != -1; i = ne[i]) {
int j = e[i];
if (!st[j]) {
int s = dfs(j, u);
res = max(res, s);
}
}
//memo[key] = res==INT_MIN?1:res+1;
memo[key] = res+1;
return memo[key];
}
static bool cmp(const vector<int>& v1, const vector<int>& v2){
return v1[0]<v2[0];
}
vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
this->n = n;
// 初始化
idx = 0;
memset(h, -1, sizeof(h));
for(int i=0; i<edges.size(); i++){
add(edges[i][0],edges[i][1]);
add(edges[i][1],edges[i][0]);
}
vector<vector<int>> res;
for(int i=0; i<n; i++){
memset(st, false, sizeof(st));
int height = dfs(i, -1);
//cout<<"node"<<i<<" "<<height<<endl;
res.push_back({height,i});
}
//对res排序
sort(res.begin(), res.end(), cmp);
vector<int> ans;
ans.push_back(res[0][1]);
for(int i=1; i<res.size(); i++){
if(res[i][0]==res[i-1][0])
ans.push_back(res[i][1]);
else
break;
}
return ans;
}
};
上面的简版
class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
memset(h, -1, sizeof(h));
int min_v=INT_MAX;
vector<int> res;
for(auto e: edges)
add(e[0], e[1]), add(e[1], e[0]);
for(int i=0; i<n; i++){
memset(st, false, sizeof(st));
int tmp = dfs(i, -1);
//cout<<tmp<<" ";
if(tmp==min_v){
res.push_back(i);
}else if(tmp<min_v){
min_v = tmp;
res.clear();
res.push_back(i);
}
}
return res;
}
private:
static const int N = 20005;
int h[N];
int ne[N];
int e[N];
int idx=0;
bool st[N];
unordered_map<int, int> memo;
// 添加点和边
void add(int a, int b){
e[idx] = b, ne[idx]=h[a], h[a] = idx++;
}
// 当前点u的树高
int dfs(int u, int root){
int key = u*1e5 +root;
st[u]=true;
if(memo.count(key)) return memo[key];
int max_v = INT_MIN;
for(int i=h[u]; i!=-1; i=ne[i]){
int j=e[i];
if(!st[j]){
int tmp = dfs(j, u);
max_v = max(max_v,tmp);
}
}
memo[key] = max_v>0?max_v+1:1; //有问题,如果一个叶子结点,不就会返回(INT_MIN+1)? 的确是这样,但是本题只需通过相对值确定点的编号,无需输出高度,故不影响
return memo[key];
}
};