leetcode 785. Is Graph Bipartite?

13 篇文章 0 订阅
3 篇文章 0 订阅

leetcode 785. Is Graph Bipartite?

题目描述

Given an undirected graph, return true if and only if it is bipartite.

Recall that a graph is bipartite if we can split it’s set of nodes into two independent subsets A and B such that every edge in the graph has one node in A and another node in B.

The graph is given in the following form: graph[i] is a list of indexes j for which the edge between nodes i and j exists. Each node is an integer between 0 and graph.length - 1. There are no self edges or parallel edges: graph[i] does not contain i, and it doesn’t contain any element twice.

Note:

  • graph will have length in range [1, 100].
  • graph[i] will contain integers in range [0, graph.length - 1].
  • graph[i] will not contain i or duplicate values.
  • The graph is undirected: if any element j is in graph[i], then i will be in graph[j].

Difficulty: medium
785. Is Graph Bipartite?


中文描述
给定一个图,问这个图是否是个二部图?
二部图的定义是,把图中的节点分成独立的两部分集合,记为AB(不存在交集),然后保证图中的所有边都的两个顶点,一个属于A,另一个属于B


输入格式
输入一个列表graph,列表的第i个元素graph[i]表示的是第i个节点相连接的节点的集合。例如graph[[1,3], [0,2], [1,3], [0,2]],表示第0个节点和第13个节点相连,第1个节点和第02个节点相连,以此类推。


Examples:

  1. Input: [[1,3], [0,2], [1,3], [0,2]]
    Output: true
    解释:
    这个图看起来是这样:
    0——1
    |·······|
    |·······|
    3——2
    我们可以把它分为两个部分: {0, 2} 和 {1, 3}.

  2. Input: [[1,2,3], [0,2], [0,1,3], [0,2]]
    Output: false
    这个图看起来是这样:
    0——1
    | ··\··· |
    | ···\·· |
    3——2
    我们无法将其分成两个部分


解答思路

考虑从第i个节点开始考虑,如果该节点i还没被放入A或则B中,则考虑把其放入A中,并且把i标记为已用。之后与i相连的节点只能放到B中,如果与i相连的节点有存在于A中的,则已经不满足条件,可以返回False。否则就对与i相连的节点重复上述操作,不过这次与这些节点相连的只能放到B中,如果有在A中的则返回False。这样在AB之间交替,直到没有未用过的节点为止。这样所有与节点i有直接或则间接联系的节点就被遍历完了。我们就可以考虑下一个与节点i无关的节点。


代码

class Solution(object):
    def isBipartite(self, graph):
        """
        :type graph: List[List[int]]
        :rtype: bool
        514ms
        """
        # 用来存放两边的节点
        subsets_A = set()
        subsets_B = set()
        # 用来存放用过的节点
        used = set()
        # 从0号节点开始考虑
        for i in range(len(graph)):
            if i not in used:
                # 没使用过的节点放到A中
                subsets_A.add(i)
                # 当前的节点集合
                cur_list = [i]
                # 用来记录是放在A还是B
                count = 0
                while cur_list:
                    next_list = []
                    # 对所有与第i个节点相连的节点都只能放到对面
                    for j in cur_list:
                        used.add(j)
                        for opposite in graph[j]:
                            # 当前节点都是A中的,与之相连的只能放到B里,如果有在A里的就无法满足题目要求
                            if count % 2 == 0:
                                if opposite in subsets_A:
                                    return False
                                subsets_B.add(opposite)
                            # 当前节点都是B中的,与之相连的只能放到A里,如果有在B里的就无法满足题目要求
                            else:
                                if opposite in subsets_B:
                                    return False
                                subsets_A.add(opposite)
                            # 只记录没被使用过的节点
                            if opposite not in used:
                                next_list.append(opposite)
                    # 当前节点变化,从A->B或则从B->A
                    count += 1
                    cur_list = next_list
        return True

写的很菜,速度也慢= =,附上其它人写的dfs的代码详细请见Python 7 lines DFS graph coloring w/ graph and Explanation

class Solution(object):
    def isBipartite(self, graph):
        """
        :type graph: List[List[int]]
        :rtype: bool
        57ms
        """
        def dfs(v, cur_color):
            # 如果v再次出现,则判断是不是是在同一边,不是同一边返回False
            if v in color:
                return color[v] == cur_color
            # 否则记录v的分在哪边
            color[v] = cur_color
            # cur_color ^ 1 用来转化A->B,或则B->A
            return all(dfs(w, cur_color ^ 1) for w in graph[v])

        color = {}
        # 如果iterable的所有元素不为0、''、False或者iterable为空,all(iterable)返回True,否则返回False;
        return all(dfs(v, 0) for v in range(len(graph)) if v not in color)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值