LeetCode547. Friends Circles 利用union find | bfs | dfs三种方法解决

来源:互联网 发布:淘宝上找货源 编辑:程序博客网 时间:2024/06/01 20:26

问题来源

此题来源于LeetCode547. Friend Circles,主要运用了并查集(union find)、广度优先遍历(bfs)和深度优先遍历(bfs)三种方法解决。

问题简述

给定一个N×N的矩阵M表示了N个人之见的朋友关系。如果M[i][j]=1那么ij是直接朋友关系;如果M[i][j]=1M[j][k]=1M[i][k]=0,那么ik是间接朋友关系。我们假定有直接和间接朋友关系的人为一个朋友圈,试问M中有几个朋友圈。
比如:

输入: [[1,1,0], [1,1,0], [0,0,1]]输出: 2解释:第0和第1个人是直接朋友,他们构成1个朋友圈;第2个人自己构成一个朋友圈,所以返回2

又比如:

输入: [[1,1,0], [1,1,1], [0,1,1]]输出: 1解释:第0和第1个人是直接朋友,第1和第2个人是直接朋友,所以第0和第2个人是间接朋友,这3个人构成了1个朋友圈,所以返回1

值得注意的是:

  • 总是有M[i][j]=M[j][i]
  • 总是有M[i][i]=1

解决方案

利用union find解决

此处的并查集用到了路径压缩的优化。

class Solution {private:    vector<int> vec;    int sz;private:    void Initialize(int count){        vec = vector<int>(count);        sz = count;        for (int i = 0; i < count; i++)            vec[i] = i;    }    int findRoot(int p){        assert(p >= 0 && p < sz);        while (vec[p] != p){            //路径压缩            vec[p] = vec[vec[p]];            p = vec[p];        }        return vec[p];    }    void unionNode(int p, int q){        assert(p >= 0 && p < sz && q >= 0 && q < sz);        int pRoot = findRoot(p);        int qRoot = findRoot(q);        if (pRoot != qRoot)            vec[pRoot] = qRoot;    }public:    int findCircleNum(vector<vector<int>>& M) {        int m = M.size();        if (0 >= m)            return 0;        Initialize(m);        for (int i = 0; i < m; i++){            for (int j = i + 1 ; j < m; j++){                if (M[i][j] == 1)                    unionNode(i, j);            }        }        int res = 0;        for (int i = 0; i < m; i++)            if (vec[i] == i)                res++;        return res;    }};

利用bfs解决

由于问题的特殊性,每次都只要把对角线上的元素放到队列当中即可。

class Solution {private:    int sz;private:    void bfs(vector<vector<int>> &M, int x){        queue<int> q;        q.push(x);        while(!q.empty()){            int newX = q.front();            q.pop();            M[newX][newX] = 0;            for (int i = 0; i < sz; i++){                if (1 == M[newX][i]){                    M[newX][i] = 0;                    M[i][newX] = 0;                    if (1 == M[i][i])                        q.push(i);                }            }        }        return;    }public:    int findCircleNum(vector<vector<int>>& M) {        int m = M.size();        if (0 >= m)            return 0;        sz = m;        int res = 0;        for (int i = 0; i < m; i++){            if (1 == M[i][i]){                bfs(M,i);                res++;            }        }               return res;    }};

利用dfs解决

dfs与bfs的思路大同小异,但元素过多可能会造成栈溢出。

class Solution {private:    int sz;private:    void dfs(vector<vector<int>> &M, int x, int y){        if (0 == M[x][y])            return;        M[x][y] = 0;        for (int i = 0; i < sz; i++){            if (1 == M[x][i]){                M[x][i] = 0;                M[i][x] = 0;                dfs(M, i, i);            }        }        return;    }public:    int findCircleNum(vector<vector<int>>& M) {        int m = M.size();        if (0 >= m)            return 0;        sz = m;        int res = 0;        for (int i = 0; i < m; i++){            if (1 == M[i][i]){                dfs(M,i,i);                res++;            }        }          return res;    }};

结束语

以上三种方法最快的是并查集(union find),bfs和dfs的速度差不多,三者也许都还有优化的余地~

原创粉丝点击