[LeetCode解题报告] 886. 可能的二分法

[LeetCode解题报告] 886. 可能的二分法

一、 题目

1. 题目描述

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

     

    Related Topics
    • 深度优先搜索
    • 广度优先搜索
    • 并查集

    • 👍 173
    • 👎 0

    2. 原题链接

    链接: 886. 可能的二分法

    二、 解题报告

    1. 思路分析

    方法1-并查集
    1. 由于题目是最多分两组,那么一个人a不喜欢的人一定都在另一组,那么按这个思路用并查集分完所有人的dislike,然后判断他是否和不喜欢的人在一组即可。
    方法2-DFS染色
    1. a是红色,a不喜欢的人都是蓝色,蓝色不喜欢的人都是红色。
    2. 处理每个人不喜欢的人将其染色,递归这个过程,如果发现要处理的人已经有颜色,且颜色冲突,则返回false

    2. 复杂度分析

    1. 并查集,用近似O(m) 的时间建立并查集,m是dislike长度,O(1)查询,建图O(m)是最坏时间复杂度O(nlog2n)
    2. DFS染色,建图O(m),因为每个人都染色,只会访问一边,因此递归O(n+m),递归深度取决于最长关系。

    3.代码实现

    下面展示一些 内联代码片
    并查集

    class Solution:
        def possibleBipartition(self, n: int, dislikes: List[List[int]]) -> bool:
            # g = collections.defaultdict(list)
            g = [[] for _ in range(n+1)]
            for u,v in dislikes:
                g[u].append(v)
                g[v].append(u)
            
            fathers = list(range(n+1))
            def find_father(x):
                if fathers[x] != x:
                    fathers[x] = find_father(fathers[x])
                return fathers[x]          
            def union(x,y):
                x = find_father(x)
                y = find_father(y)
                fathers[x] = y    
           
            for i in range(1,n+1):
                if len(g[i]) == 0:
                    continue
                neighbor1 = g[i][0]
                
                for neighbor2 in g[i]:
                    union(neighbor1,neighbor2)
                
                if find_father(i) == find_father(neighbor1):
                    return False
    
            return True        
    

    DFS染色

    class Solution:
        def possibleBipartition(self, n: int, dislikes: List[List[int]]) -> bool:
            # g = collections.defaultdict(list)
            g = [[] for _ in range(n+1)]
            for u,v in dislikes:
                g[u].append(v)
                g[v].append(u)
            
            colors = {}
            def dfs(node,color):
                c = colors.get(node)
                if c:
                    return c == color
                colors[node] = color
    
                return all(dfs(n,color^1) for n in g[node])
            
            return all(dfs(n,0) for n in  range(1, n+1) if n not in colors)
    

    三、 本题小结

    1. dfs比较容易想
    2. 并查集一般是用来解决分成同一类,这题给出的直接条件是"不可在同一类",但是由于限制了只能两组,因此这个"不可在同一类"可以认为是:u的所有邻居v都在同一类
    • 0
      点赞
    • 0
      收藏
      觉得还不错? 一键收藏
    • 0
      评论

    “相关推荐”对你有帮助么?

    • 非常没帮助
    • 没帮助
    • 一般
    • 有帮助
    • 非常有帮助
    提交
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值