LeetCode 0886. 可能的二分法

64 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第16天,点击查看活动详情

【LetMeFly】886.可能的二分法:图搜索

力扣题目链接:leetcode.cn/problems/po…

给定一组 n 人(编号为 1, 2, ..., n), 我们想把每个人分进任意大小的两组。每个人都可能不喜欢其他人,那么他们不应该属于同一组。

给定整数 n 和数组 dislikes ,其中 dislikes[i] = [ai, bi] ,表示不允许将编号为 ai 和  bi的人归入同一组。当可以用这种方法将所有人分进两组时,返回 true;否则返回 false

 

示例 1:

输入:n = 4, dislikes = [[1,2],[1,3],[2,4]]
输出:true
解释:group1 [1,4], group2 [2,3]

示例 2:

输入:n = 3, dislikes = [[1,2],[1,3],[2,3]]
输出:false

示例 3:

输入:n = 5, dislikes = [[1,2],[2,3],[3,4],[4,5],[1,5]]
输出:false

 

提示:

  • 1 <= n <= 2000
  • 0 <= dislikes.length <= 104
  • dislikes[i].length == 2
  • 1 <= dislikes[i][j] <= n
  • ai < bi
  • dislikes 中每一组都 不同

 

方法一:广度优先搜索

可以把题目理解为:nn个节点的无向图,其中dislikesdislikes为边

这样,我们就能很容易地把图构建出来:

vector<vector<int>> graph(n + 1);
for (auto& v : dislikes) {
    graph[v[0]].push_back(v[1]);
    graph[v[1]].push_back(v[0]);
}

图构建完毕后,对图进行搜索。

因为图可能不连通,因此当发现一个新的图的节点时,用哈希表记录下这个连通子图中的节点。

这样,在图遍历过程中,我们就可以很容易地知道是否出现了“环”

遍历过程中,我们给节点编号(分组),编号只有“1”和“2”

如果某个节点的相邻节点已有编号,就看这两个节点的编号是否相同。

若相邻两个节点编号相同,则分组失败,返回false

若图成功遍历完毕,则返回true

  • 时间复杂度O(n+m)O(n + m),其中nn是节点个数,mm是边的个数
  • 空间复杂度O(n+m)O(n + m)

AC代码

C++

class Solution {
public:
    bool possibleBipartition(int n, vector<vector<int>>& dislikes) {
		// 建图
        vector<vector<int>> graph(n + 1);
        for (auto& v : dislikes) {
            graph[v[0]].push_back(v[1]);
            graph[v[1]].push_back(v[0]);
        }
		// 遍历
        vector<bool> visited(n + 1, false);  // visited[i]表示节点i是否被遍历过
        vector<int> node(n + 1);  // node[i]表示节点i的编号
        for (int i = 1; i <= n; i++) {  // 查看每一个节点
            if (!visited[i]) {  // 若是一个未遍历过的新节点,则说明这是一个新的“子图”的节点
                visited[i] = true;  // 标记为遍历过
                node[i] = 1;  // 赋编号
                unordered_set<int> appeared;  // 用来记录这个子图中都有哪些节点
                appeared.insert(i);
                queue<int> q;  // 广搜队列
                q.push(i);
                while (q.size()) {
                    int thisNode = q.front();  // 取出节点
                    q.pop();
                    for (int toNode : graph[thisNode]) {  // 节点临边
                        if (!visited[toNode]) {  // 第一次遍历到
                            visited[toNode] = true;
                            node[toNode] = node[thisNode] == 1 ? 0 : 1;
                            appeared.insert(toNode);
                            q.push(toNode);
                        }
                        else {
                            if (appeared.count(toNode)) {  // 这俩点相连
                                if (node[thisNode] == node[toNode])
                                    return false;  // !!!!!!!!
                            }
                        }
                    }
                }
            }
        }
        return true;
    }
};

同步发文于CSDN,原创不易,转载请附上原文链接哦~ Tisfy:letmefly.blog.csdn.net/article/det…