LeetCode 0886. 可能的二分法

Posted Tisfy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 0886. 可能的二分法相关的知识,希望对你有一定的参考价值。

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

力扣题目链接:https://leetcode.cn/problems/possible-bipartition/

给定一组 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 中每一组都 不同

     

    方法一:广度优先搜索

    可以把题目理解为: n n n个节点的无向图,其中 d i s l i k e s dislikes 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]);
    
    

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

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

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

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

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

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

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

    • 时间复杂度 O ( n + m ) O(n + m) O(n+m),其中 n n n是节点个数, m m m是边的个数
    • 空间复杂度 O ( n + m ) 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:https://letmefly.blog.csdn.net/article/details/127344544

    以上是关于LeetCode 0886. 可能的二分法的主要内容,如果未能解决你的问题,请参考以下文章

    886. 可能的二分法 : 判定二分图模板题

    LeetCode 886 可能的二分法[dfs] HERODING的LeetCode之路

    [LeetCode] Possible Bipartition 可能的二分图

    LeetCode 题集:二分搜索

    LeetCode 题集:二分搜索

    LeetCode 35 搜索插入位置[二分法] HERODING的LeetCode之路