310.最小高度树

题目

310.最小高度树

题目大意

树是一个无向图,其中任何两个顶点只通过一条路径连接。 换句话说,一个任何没有简单环路的连通图都是一棵树。

给你一棵包含 n 个节点的树,标记为 0n - 1 。给定数字 n 和一个有 n - 1 条无向边的 edges 列表(每一个边都是一对标签),其中 edges[i] = [ai, bi] 表示树中节点 aibi 之间存在一条无向边。

可选择树中任何一个节点作为根。当选择节点 x 作为根节点时,设结果树的高度为 h 。在所有可能的树中,具有最小高度的树(即,min(h))被称为 最小高度树

请你找到所有的 最小高度树 并按 任意顺序 返回它们的根节点标签列表。

树的 高度 是指根节点和叶子节点之间最长向下路径上边的数量。

样例

示例 1:

img

输入:n = 4, edges = [[1,0],[1,2],[1,3]]
输出:[1]
解释:如图所示,当根是标签为 1 的节点时,树的高度是 1 ,这是唯一的最小高度树。

示例 2:

img

输入:n = 6, edges = [[3,0],[3,1],[3,2],[3,4],[5,4]]
输出:[3,4]

数据规模

提示:

  • 1 < = n < = 2 ∗ 1 0 4 1 <= n <= 2 * 10^4 1<=n<=2104
  • edges.length == n - 1
  • 0 <= ai, bi < n
  • ai != bi
  • 所有 (ai, bi) 互不相同
  • 给定的输入 保证 是一棵树,并且 不会有重复的边

思路

题目中给定的含有 n n n个节点的树,有如下特点:

  • 树中的共有 n − 1 n-1 n1 条不同的边;
  • 任意两个节点之间有且仅有一条路径;
  • 叶子节点的度为 1 1 1,非叶子节点的度至少为 2 2 2
  • 树的高度由根节点到叶子节点的最大距离决定。

考虑常规做法,就是寻找最长链,而寻找最长链的方法就是先随机选择一个节点(比如 0 0 0号节点)开始遍历,找到离 0 0 0号节点的最远的节点 x x x(可能不止一个,随便选择一个即可),然后再以 x x x作为起点遍历,找到离 x x x最远的节点 y y y,那么路径 x → y x\rightarrow y xy就是最长链,然后用pre数组记录回边,用path导出最长链。如果最长链的结点数是奇数,那么边数就是偶数,刚好最中间的点就是所求的根节点;如果最长链的结点数是偶数,那么边数就是奇数,刚好最中间的两个点就是所求的根节点。

代码

// short int long float double bool char string void
// array vector stack queue auto const operator
// class public private static friend extern 
// sizeof new delete return cout cin memset malloc
// relloc size length memset malloc relloc size length
// for while if else switch case continue break system
// endl reverse sort swap substr begin end iterator
// namespace include define NULL nullptr exit equals 
// index col row arr err left right ans res vec que sta
// state flag ch str max min default charray std
// maxn minn INT_MAX INT_MIN push_back insert
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int>PII;
typedef pair<int, string>PIS;
const int maxn=3e4+50;//注意修改大小
long long read(){long long x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}while(isdigit(c)){x=x*10+c-'0';c=getchar();}return x*f;}
ll qpow(ll x,ll q,ll Mod){ll ans=1;while(q){if(q&1)ans=ans*x%Mod;q>>=1;x=(x*x)%Mod;}return ans%Mod;}

class Solution {
public:
	void dfs(int u,vector<int>&dist,vector<int>&pre,vector<vector<int>>&e){
		for(auto v:e[u]){
			if(!dist[v]){
				dist[v]=dist[u]+1;
				pre[v]=u;
				dfs(v,dist,pre,e);
			}
		}
	}
	int find(int u,vector<int>&pre,vector<vector<int>>&e){
		int n=e.size();
		vector<int>dist(n);
		dist[u]=1;
		dfs(u,dist,pre,e);
		int maxdist=0,x=-1;
		for(int i=0;i<n;i++){
			if(dist[i]>maxdist){
				maxdist=dist[i];x=i;
			}
		}
		return x;
	}
    vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
		if(n==1){
			return {0};
		}
		vector<vector<int>>e(n);
		vector<int>pre(n,-1);
		for(auto it:edges){
			e[it[0]].push_back(it[1]);
			e[it[1]].push_back(it[0]);
		}
		int x=find(0,pre,e);
		int y=find(x,pre,e);
		pre[x]=-1;
		vector<int>path;
		while(y!=-1){
			path.push_back(y);
			y=pre[y];
		}
		if(path.size()%2){
			return {path[path.size()/2]};
		}
		else{
			return {path[path.size()/2-1],path[path.size()/2]};
		}
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Phoenix_ZengHao

创作不易,能否打赏一瓶饮料?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值