LeetCode:310 最小高度树 反向bfs

对于一个具有树特征的无向图,我们可选择任何一个节点作为根。图因此可以成为树,在所有可能的树中,具有最小高度的树被称为最小高度树。给出这样的一个图,写出一个函数找到所有的最小高度树并返回他们的根节点。

格式

该图包含 n 个节点,标记为 0 到 n - 1。给定数字 n 和一个无向边 edges 列表(每一个边都是一对标签)。

你可以假设没有重复的边会出现在 edges 中。由于所有的边都是无向边, [0, 1]和 [1, 0] 是相同的,因此不会同时出现在 edges 里。

示例 1:
在这里插入图片描述

示例 2:
在这里插入图片描述

说明:
根据树的定义,树是一个无向图,其中任何两个顶点只通过一条路径连接。 换句话说,一个任何没有简单环路的连通图都是一棵树。
树的高度是指根节点和叶子节点之间最长向下路径上边的数量。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-height-trees
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

正向bfs

第一个想到的思路就是枚举起点依次bfs,不断更新答案,然后会超时

class Solution {
public:
    int bfs(int begin, int n, vector<vector<int>>& edges)
    {
        vector<bool> vis(n, false);
        deque<int> q; q.push_back(begin);
        int ans = 0;
        while(!q.empty())
        {
            ans++;
            int qs = q.size();
            for(int i=0; i<qs; i++)
            {
                int tp=q.front(); q.pop_front(); int next=INT_MAX;
                vis[tp] = true;
                for(int e=0; e<edges.size(); e++)
                {
                    if(edges[e][0]==tp) next=edges[e][1];
                    else if(edges[e][1]==tp) next=edges[e][0];
                    if(next!=INT_MAX && !vis[next]) q.push_back(next);
                }
            }
        }
        return ans;
    }
    vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges)
    {
        int mindis = INT_MAX;
        vector<int> ans;
        for(int i=0; i<n; i++)
        {
            int dis = bfs(i, n, edges);
            if(dis==mindis) 
                ans.push_back(i);
            else if(dis<mindis)
            {
                mindis = dis;
                ans.erase(ans.begin(), ans.end());
                ans.push_back(i);
            }
        }
        return ans;
    }
};

反向bfs

正确的思路是:由分析可以知道最后的答案一定是一个或者两个节点,那么可以使用 “反向的bfs”,即不从起点,而是从叶子节点开始访问

  • 每次遍历访问叶子节点(相当于每次都删除叶子节点)直到最后节点数少于3

最后剩下的未被访问的节点就是我们要找的答案了,相比于枚举起点的正向bfs,这种反向的bfs更适合起点与答案有关的场合

正向bfs复杂度为O(n*n*e),其中一个n是枚举起点,另一个n是一次bfs中访问的n个节点,e是查找邻接关系需要的时间

反向bfs的复杂度为 O(n*e),因为不用枚举起点所以快了n倍

代码

class Solution {
public:
    vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges)
    {
        vector<bool> vis(n, false);
        int CNT = n;
        while(CNT>2)
        {
        	// 在未被访问的集合中且出现次数为1的节点是叶子节点
            vector<int> cnt(n, 0);
            for(int e=0; e<edges.size(); e++)
            {
                if(!vis[edges[e][0]]&&!vis[edges[e][1]])
                {
                    cnt[edges[e][0]]++; 
                    cnt[edges[e][1]]++;
                }
            }
            for(int i=0; i<n; i++)
                if(cnt[i]==1)  {vis[i]=true; CNT--;}
        }
        vector<int> ans;
        for(int i=0; i<n; i++)
            if(!vis[i]) ans.push_back(i);
        return ans;
    }
};
发布了199 篇原创文章 · 获赞 7 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44176696/article/details/104680245
今日推荐