310. Minimum Height Trees Add to List

LeetCode

  • 题目地址:https://leetcode.com/problems/minimum-height-trees/#/description
  • 思考过程:

    • 题目要求是给一个具有树的属性的无向图,即每个点仅被另一条边连在一起,也就是说对于n个节点的图,只有n-1条边。题目目的是要找到其中一个节点作为根节点,能使得整个树的高度最小,这样的树叫做Minimum Height Tree(MHT)。
    • 于是我一开始的想法很简单,(1)先根据输入构造边的一个map,(2)然后对从第0~n-1节点,计算一次深度,(3)最后根据深度的大小来返回MHT的根节点。但是这么做会在n=1000左右的时候超时,时间复杂度应该是O( n2 ),因为一共有n个点,每个点计算以它为根的深度,通过BFS来计算,复杂度是O(V+2E),因为是无向图每条边最多需要判断两次,每个点遍历一次,而V=n,E=n-1,复杂度即O( n <script type="math/tex" id="MathJax-Element-242">n</script>),这样的过程有n次
    • 然后参考了一下solution,只看了一下人家的思路,然后自己理解后写,思路大概是这样的,每次找到只有一条边连着的节点,剔除它,并剔除所有和他相连的边,最后剩下一个点或者两个点(一起连着,都是MHT的根节点),对于这个的时间复杂度就是O(V+E),因为对于每个点只访问一次,并且删除,同时对于每个边删除一次,由于V=n,E=n-1,所以O(n)
    • 最后我的代码和答案的代码的对比,最主要的区别就是存储的时候,我用的是map,而答案用的是vector。这里我用map的原因是,每次检查到与该节点连接的边个数只有1的时候,需要把该节点删除,而map删除比vector快。但是答案的思路应该是每个节点只有一次机会,边数会变成1(变成是一个过程,从2然后erase一条边之后变成1),而之前边数是1的点不需要删除,因为下次再到它的时候(一定会再到它,因为无向图边是双向的),它的边数从1变成0,不会被考虑进去,也即相当于删除了,而在这里他节省了一些时间,所以我的算法和它的应该在常数项中会有点区别,毕竟对于unordered_map这种哈希map的删除时间应该是O(1)的,那么每次计算,我的复杂度会多O(n),但是总共的复杂度仍然是O(n)
  • 代码
    这是最开始自己的思路,超时

class Solution {
public:
    vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
        vector<int> v; 
        int min = INT_MAX;
        //construct m
        for (vector<pair<int,int>>::iterator it = edges.begin(), end = edges.end(); it != end; it++) {
            int one = it->first, two = it->second;
            m[one].push_back(two);
            m[two].push_back(one);
        }
        bool visit[n];
        for (int i = 0; i < n; i++) {
            memset(visit,0,sizeof(visit));
            int dep = depthWithNode(i,visit);
            //cout << "i: " << i << " dep: " << dep << endl;
            if (dep < min) {
                v.clear();
                v.push_back(i);
                min = dep;
            } else if (dep == min)
                v.push_back(i);
        }
        return v;
    }
    //calculate depth with root node k
    int depthWithNode(int k, bool* visit) {
        //initial
        clearCur();
        clearNext();
        cur.push(k);
        visit[k] = true;
        int height = 0;

        while (!cur.empty()) {
            height++;
            while (!cur.empty()) {
                int tmp = cur.front();
                cur.pop();
                for (int i = 0; i < m[tmp].size(); i++) {
                    if (!visit[m[tmp][i]]) {
                        next.push(m[tmp][i]);
                        visit[m[tmp][i]] = true;
                    }
                }
            }
            cur = next;
            clearNext();
        }
        return height;
    }
    void clearCur() {
        while (!cur.empty())
            cur.pop();
    }
    void clearNext() {
        while (!next.empty())
            next.pop();
    }
private:
    map<int,vector<int>> m;
    queue<int> cur;
    queue<int> next;
};

这是后来参考的思路,自己实现的,大概用时116ms

class Solution {
public:
    vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
        vector<int> v(1,0); 
        //construct m
        for (vector<pair<int,int>>::iterator it = edges.begin(), end = edges.end(); it != end; it++) {
            int one = it->first, two = it->second;
            m[one].insert(two);
            m[two].insert(one);
        }
        while(m.size()) {
            v.clear();
            if (m.size() == 1) {
                v.push_back(m.begin()->first);
                break;
            }
            for (unordered_map<int,set<int>>::iterator it = m.begin(), end = m.end(); it != end; it++) {
                if (it->second.size() == 1)
                    v.push_back(it->first);
            }
            int leafSize = v.size();
            for (int i = 0; i < leafSize; i++) {
                for (set<int>::iterator it = m[v[i]].begin(), end = m[v[i]].end(); it != end; it++) {
                    m[*it].erase(v[i]);
                }
                m.erase(v[i]);
            }
        }
        sort(v.begin(),v.end());
        return v;
    }
private:
    unordered_map<int,set<int>> m;
};

这是答案的代码,和我写的有一点点不同,不同在思路中写到了这里不重复,大概耗时43ms

class Solution {
 public:
  vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
    // Initialize the undirected graph
    vector<set<int>> adj(n);
    for (vector<pair<int,int>>::iterator it = edges.begin(), end = edges.end(); it != end; it++) {
      adj[it->first].insert(it->second);
      adj[it->second].insert(it->first);
    }
    // Corner case
    vector<int> current;
    if (n == 1) {
      current.push_back(0);
      return current;
    }
    // Create first leaf layer
    for (int i = 0; i < adj.size(); ++i) {
      if (adj[i].size() == 1) {
        current.push_back(i);
      }
    }
    // BFS the graph
    while (true) {
      vector<int> next;
      for (int node : current) {
        for (int neighbor : adj[node]) {
          adj[neighbor].erase(node);
          if (adj[neighbor].size() == 1) next.push_back(neighbor);
        }
      }
      if (next.empty()) return current;
      current = next;
    }
  }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值