leetcode310 最小高度树 题解

题面

原来的题面
大致意思是给你一个树,然后让你选择一些点作为根,使得树的高度最小。

题解

先说结论,在树的直径上,位于中间的一个或者两个点(奇数就是一个点,偶数就是一个点),至于树的直径是啥,就是树上最长的一条路径,大家可以去搜索一下。
那么怎么求这个直径呢?一般我们从一个随机的点 a a a 出发,找到距离他最远的一个点 b b b ,然后再次从 b b b 点出发,找到距离 b b b 点最远的点 c c c ,那么从 b b b c c c 的路径就是这棵树的一条直径。
而对于直径来说,考虑他的性质,我们发现。
第一种情况
例如上图,有好几个直径,并且有分叉,分为两个部分({5,6,7} 和 {0,1,2,3,4}),{5,6,7} 组成直径更长的一半,剩下的组成更短的一半,我们发现即使路径长度是偶数(大家可以自己画一下),我们需要的点也是在一条简单路径下。
所以我们先用 dfs 求出直径的长度和任意一个直径的任意一个端点,然后从这个端点继续 dfs,当通过回溯发现这是一个处于直径上的端点时,我们再次判断目前距离是否是整个长度的一半,如果是的话就把这个端点存下来。

代码

class Solution
{
public:
    vector<int> findMinHeightTrees(int n, vector<vector<int>> &edges)
    {
#define maxn 20005
        vector<int> to[maxn];
        for (int i = 0; i < edges.size(); i++) // 建一个无向图
            to[edges[i][0]].push_back(edges[i][1]), to[edges[i][1]].push_back(edges[i][0]);
        int max_dis = 0, pos = -1;
        function<void(int, int, int)> dfs = [&](int x, int dis, int fa) // 用于查找直径长度和端点的函数
        {
            if (dis > max_dis)
            {
                max_dis = dis;
                pos = x;
            }
            for (int i = 0; i < to[x].size(); i++)
            {
                int v = to[x][i];
                if (v == fa)
                    continue;
                dfs(v, dis + 1, x);
            }
        };
        dfs(0, 1, -1); // 先找端点 b
        dfs(pos, 1, -1); // 在找 c 的同时,再找直径长度 
        vector<int> ans;
        int halfDis1 = (max_dis + 1) / 2; // 距离端点的长度有两种可能性
        int halfDis2 = (max_dis % 2 == 0 ? halfDis1 + 1 : halfDis1);
        function<bool(int, int, int)> dfs1 = [&](int x, int dis, int fa) // 找根
        {
            bool f = false; 
            if (dis == max_dis) // 说明之前经过的点是直径上的点
                f = true;
            for (int i = 0; i < to[x].size(); i++)
            {
                int v = to[x][i];
                if (v == fa)
                    continue;
                if (dfs1(v, dis + 1, x)) // 回溯发现目前所处的点在直径上
                    f = true;
            }
            if ((dis == halfDis1 || dis == halfDis2) && f == true) // 如果发现这个点距离端点的距离恰好是直径长度的一般,这个点可以作为根
                ans.push_back(x);
            return f;
        };
        dfs1(pos, 1, -1);
#undef maxn
        return ans;
    }
};

然后就搞定了,但是为啥大家都这么快……
结果
作者能力有限,如果有任何错误之处,还请各位指教。(~ ̄▽ ̄)~

  • 22
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值