leetcode-pp / 91alg-5-daily-check

91 天学算法第五期打卡
55 stars 14 forks source link

【Day 30 】2021-10-09 - 886. 可能的二分法 #47

Open azl397985856 opened 3 years ago

azl397985856 commented 3 years ago

886. 可能的二分法

入选理由

暂无

题目地址

https://leetcode-cn.com/problems/is-graph-bipartite/

前置知识

每个人都可能不喜欢其他人,那么他们不应该属于同一组。

形式上,如果 dislikes[i] = [a, b],表示不允许将编号为 a 和 b 的人归入同一组。

当可以用这种方法将每个人分进两组时,返回 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 <= 10000 dislikes[i].length == 2 1 <= dislikes[i][j] <= N dislikes[i][0] < dislikes[i][1] 对于dislikes[i] == dislikes[j] 不存在 i != j

leo173701 commented 3 years ago
class Solution:
    def possibleBipartition(self, N, dislikes):
        # Write your code here.
        visited = [0 for i in range(N)];
        adj = [[] for i in range(N)];
        for dis in dislikes:
            adj[dis[0]-1].append(dis[1]-1);
            adj[dis[1]-1].append(dis[0]-1);

        for i in range(0,N):
            if visited[i] == 0:
                visited[i] = 1;
                if not self.DFS(i, visited, adj):
                    return False;
        return True;
    def DFS(self,cur,visited,adj):
        for j in adj[cur]:
            if visited[j] == 0:
                visited[j] = -visited[cur];
                if not self.DFS(j, visited, adj):
                    return False;
            elif visited[j] == visited[cur]:
                return False;
        return True;
FullStackH commented 3 years ago

class Solution: def isBipartite(self, graph: List[List[int]]) -> bool: n = len(graph) color = [0] * n

    def dfs(node, c):
        if color[node] == -c: return False
        if color[node] == c: return True
        color[node] = c
        for neighbor in graph[node]:
            if not dfs(neighbor, -c):
                return False
        return True

    for i in range(n):
        if color[i] == 0 and not dfs(i, 1):
            return False
    return True
yachtcoder commented 3 years ago

Try to color each node and its neighbors with two different colors while traversing via DFS or BFS. Because the graph might not be connected, need to make sure every node is visited. O(V+E) O(V)

DFS

class Solution:
    def isBipartite(self, graph: List[List[int]]) -> bool:
        def dfs(node, color, colorof):
            colorof[node] = color
            for next in graph[node]:
                if next in colorof and colorof[next] == color:
                    return False
                elif next not in colorof and dfs(next, color ^ 1, colorof) == False:
                    return False
            return True
        colorof = {}
        for n in range(len(graph)):
            if n not in colorof and dfs(n, 0, colorof) == False: 
                return False
        return True

BFS

class Solution:
    def isBipartite(self, graph: List[List[int]]) -> bool:
        colorof = {}
        def traverse(start, colorof):
            queue = deque([start])
            color = 0
            colorof[start] = color
            while queue:
                N = len(queue)
                color ^= 1
                for _ in range(N):
                    node = queue.popleft()
                    for next in graph[node]:
                        if next not in colorof:
                            queue.append(next)
                            colorof[next] = color
                        elif colorof[next] != color:
                            return False
            return True
        for n in range(len(graph)):
            if n not in colorof and traverse(n, colorof) == False:
                return False
        return True
yanglr commented 3 years ago

思路:

基于图的染色算法来做, 试着将一组node染成红色, 另一组染成蓝色, 如果遍历完没冲突, 就返回true, 否则返回false.

方法: 图的染色算法(dfs方式)

基于dfs来做, 遍历, 将当前 node染成红色, 将其neighbor结点都染成蓝色。

代码:

实现语言: C++

class Solution {
    vector<vector<int>> G;
    vector<int> _colors;
public:
    bool possibleBipartition(int n, vector<vector<int>>& dislikes)
    {
        G = vector<vector<int>>(n);
        for (const auto& d : dislikes)
        {
            G[d[0] - 1].push_back(d[1] - 1);
            G[d[1] - 1].push_back(d[0] - 1);
        }
        _colors = vector<int>(n, 0); // 0: 没颜色, 1: 染成红色, -1: 染成蓝色
        for (int i = 0; i < n; i++)
            if (_colors[i] == 0 && !dfs(i, 1))
                return false;
        return true;
    }
    bool dfs(int cur, int color)
    {
        _colors[cur] = color;
        for (int next : G[cur])
        {
            if (_colors[next] == color)
                return false;
            if (_colors[next] == 0 && !dfs(next, -color))
                return false;
        }
        return true;
    }    
};

复杂度分析

pophy commented 3 years ago

思路

Java Code

class Solution {    
    int[] visited;    
    public boolean isBipartite(int[][] graph) {
        int n = graph.length;
        visited = new int[n];
        for (int node = 0; node < n; node++) {
            if (visited[node] == 0 && !dfs(graph, node, 1)) {
                return false;
            }
        }
        return true;
    }

    private boolean dfs(int[][] graph, int node, int color) {
        if (visited[node] != 0) {
            return visited[node] == color;
        }
        visited[node] = color;
        for (int next : graph[node]) {
            if (!dfs(graph, next, -color)) {
                return false;
            }
        }
        return true;    
    }    
}

时间&空间

JiangyanLiNEU commented 3 years ago

DFS + Color: Runtime = O(n+m), Space = O(n)

Python Code
class Solution(object):
    def possibleBipartition(self, n, dislikes):
        color = [-1 for i in range(n+1)]

        # Create graph
        enermy = defaultdict(list)

        for [p1, p2] in dislikes:
            enermy[p1].append(p2)
            enermy[p2].append(p1)

        need_to_color = set([i for i in range(1,n+1)])

        # Color + DFS
        dye = 1
        def dfs(index, what_color):
            if index not in need_to_color:
                if color[index] == 1-what_color:
                    return False
                else:
                    return True
            else:
                color[index] = what_color
                need_to_color.remove(index)
                for dislike in enermy[index]:
                    if dfs(dislike, 1-what_color)==False:
                        return False
                return True

        for i in range(1,n+1):
            if i in need_to_color and i in enermy:
                color[i] = dye
                need_to_color.remove(i)
                for dislike in enermy[i]:
                    if dfs(dislike, 1-dye)==False:
                        print(color)
                        return False
        return True
JavaScript Code
var possibleBipartition = function(n, dislikes) {
    var dfs = (index, what_color) => {
        if (need_color.has(index)){
             color[index] = what_color;
             need_color.delete(index);
             for (enermy of graph.get(index)){
                 if (!dfs(enermy, 1-what_color)) return false;
             };
             return true;
         }else{
             if (color[index] === 1-what_color) return false;
             return true;
         }
     }
//     Build graph
    const graph = new Map();
    for ([p1,p2] of dislikes){
        if (graph.has(p1)) graph.get(p1).push(p2);
        else graph.set(p1, [p2]);
        if (graph.has(p2)) graph.get(p2).push(p1);
        else graph.set(p2, [p1]);
    };

    const dye = 1;
    let color = [];
    var need_color = new Set()
    for (let i=0; i<=n; i++){
        color.push(-1);
        need_color.add(i);
    };

    for (person of graph.keys()){
        if (need_color.has(person)){
            color[person] = dye;
            need_color.delete(person);
            for (enermy of graph.get(person)){
                if (!dfs(enermy, 1-dye)) return false;
            };
        }else{
            for (enermy of graph.get(person)){
                if (!dfs(enermy, 1-color[person])) return false;
            };
        }
    };
    return true;  
};
xj-yan commented 3 years ago
class Solution {
    public boolean possibleBipartition(int n, int[][] dislikes) {
        List<List<Integer>> notSameGroupList = new ArrayList<>();
        for (int i = 0; i <= n; i++) notSameGroupList.add(new ArrayList<>());

        for (int[] dislike : dislikes){
            notSameGroupList.get(dislike[0]).add(dislike[1]);
            notSameGroupList.get(dislike[1]).add(dislike[0]);
        }

        int[] colors = new int[n + 1];

        for (int i = 1; i <= n; i++){
            if (colors[i] == 0 && !dfs(notSameGroupList, i, 1, colors)){
                return false;
            }
        }
        return true;
    }

    private boolean dfs(List<List<Integer>> list, int i, int color, int[] colors){
        colors[i] = color;

        for (int next : list.get(i)){
            if (colors[next] == -color) continue; 
            if (colors[next] == color || !dfs(list, next, -color, colors)) return false;
        }
        return true;
    }
}

Time Complexity: O(V + E), Space Complexity: O(V)

BpointA commented 3 years ago

思路

bfs二分法(参考785题解思路)

Python3代码

class Solution:
    def possibleBipartition(self, n: int, dislikes: List[List[int]]) -> bool:
        graph=defaultdict(list)
        for a,b in dislikes:
            graph[a-1].append(b-1)
            graph[b-1].append(a-1)
        color=[0]*n
        stk=[]

        for i in range(n):
            if color[i]==0:
                color[i]=1
                stk.append(i)
            while len(stk)>0:
                p=stk.pop(0)
                for j in graph[p]:
                    if color[j]==0:
                        color[j]=3-color[p]
                        stk.append(j)
                    elif color[j]==color[p]:
                        return False
                    else:
                        continue
        return True

复杂度

时间复杂度:O(m+n),m为边数,n为点数。

空间复杂度:O(n),为color和graph长度

LAGRANGIST commented 3 years ago

class Solution: def possibleBipartition(self, N, dislikes):

Write your code here.

    visited = [0 for i in range(N)];
    adj = [[] for i in range(N)];
    for dis in dislikes:
        adj[dis[0]-1].append(dis[1]-1);
        adj[dis[1]-1].append(dis[0]-1);

    for i in range(0,N):
        if visited[i] == 0:
            visited[i] = 1;
            if not self.DFS(i, visited, adj):
                return False;
    return True;
def DFS(self,cur,visited,adj):
    for j in adj[cur]:
        if visited[j] == 0:
            visited[j] = -visited[cur];
            if not self.DFS(j, visited, adj):
                return False;
        elif visited[j] == visited[cur]:
            return False;
    return True;
falconruo commented 3 years ago

思路: 染色法求解二分图

  1. 递归DFS
  2. 迭代BFS

复杂度分析:

  1. 时间复杂度: O(N + M), 其中 N 和 M 分别是无向图中的点数和边数
  2. 空间复杂度: O(N)

代码(C++):

方法一、递归 (DFS)
class Solution {
public:
    bool isBipartite(vector<vector<int>>& graph) {
        int n = graph.size();
        // each node has 3 states: 0 - uncolored, not 0 - colored (1 - red, -1 - black)
        vector<int> colors(n);

        for (int i = 0; i < n; ++i) {
            if (colors[i] == 0 & !paint(graph, 1, i, colors))
                return false;
        }

        return true;
    }
private:
    bool paint(vector<vector<int>>& graph, int color, int node, vector<int>& colors) {
        if (colors[node] != 0) return colors[node] == color;

        colors[node] = color;

        for (int i : graph[node]) {
            if (!paint(graph, -1 * color, i, colors))
                return false;
        }

        return true;
    }
};

方法二、迭代法 (BFS)
class Solution {
public:
    bool isBipartite(vector<vector<int>>& graph) {
        int n = graph.size();
        vector<int> colors(n);

        for (int i = 0; i < n; ++i) {
            if (colors[i] != 0) continue;

            colors[i] = 1; // paint color: 1
            queue<int> qt;
            qt.push(i);

            while (!qt.empty()) {
                int t = qt.front();
                qt.pop();

                for (auto a : graph[t]) { 
                    if (colors[a] == colors[t]) return false; 

                    if (colors[a] == 0) {
                        colors[a] = -1 * colors[t]; 
                        qt.push(a);
                    }
                }
            }
        }

        return true;
    }
};
Menglin-l commented 3 years ago

思路:

BFS

从任一顶点开始遍历,同时用两种不同颜色分别标记被访问的顶点和与它相邻的顶点。如果发现有相邻顶点颜色相同,返回false;如果遍历完毕,没有任何一对相邻顶点颜色相同,返回true。


代码部分:

class Solution {
    public boolean possibleBipartition(int n, int[][] dislikes) {
        int[] visited = new int[n + 1]; 
        List<Integer>[] dislikeGraph = new List[n + 1]; 

        for (int i = 1; i < n + 1; i ++) {
            dislikeGraph[i] = new ArrayList<>();
        }

        for (int[] dislike : dislikes) {
            dislikeGraph[dislike[0]].add(dislike[1]);
            dislikeGraph[dislike[1]].add(dislike[0]);
        }

        for (int i = 1; i < n; i ++) {
            if (visited[i] > 0) {
                continue;
            }

            Queue<Integer> que = new LinkedList<>();
            que.offer(i);
            visited[i] = 1;
            while (!que.isEmpty()) {
                int v = que.poll();
                // 遍历所有相邻顶点
                for (int neighbor : dislikeGraph[v]) {
                    if (visited[neighbor] != 0) {
                        if (visited[neighbor] == visited[v]) {
                            return false;
                        }
                    } else {
                        visited[neighbor] = visited[v] == 1 ? 2 : 1;
                        que.offer(neighbor);
                    }
                }
            }
        }

        return true;
    }
}

复杂度:

Time: O(V + E) 顶点数 + 边数

Space: O(V) 顶点数

thinkfurther commented 3 years ago

思路

用color数组记录当前的分组情况,然后用dfs判断非一组的成员是否能够分类到另外一组

代码

class Solution:
    def dfs(self, i, color):
        self.colors[i] = color
        for next in self.graph[i]:
            if self.colors[next] == color:
                return False
            if self.colors[next] == 0 and not self.dfs(next, -1 * color):
                return False
        return True

    def possibleBipartition(self, N: int, dislikes: List[List[int]]) -> bool:
        import collections
        self.graph = collections.defaultdict(list)
        self.colors = [0] * N

        for a, b in dislikes:
            self.graph[a - 1].append(b - 1)
            self.graph[b - 1].append(a - 1)
        for i in range(N):
            if self.colors[i] == 0 and not self.dfs(i, 1):
                return False
        return True

复杂度

时间复杂度 :O(V+E)

空间复杂度:O(V+E)

ivalkshfoeif commented 3 years ago
class Solution {
    ArrayList<Integer>[] graph;
    Map<Integer, Integer> color;
    public boolean possibleBipartition(int n, int[][] dislikes) {
        graph = new ArrayList[n + 1];
        for (int i = 1; i <= n; i++){
            graph[i] = new ArrayList<>();
        }
        for (int[] edge: dislikes){
            graph[edge[0]].add(edge[1]);
            graph[edge[1]].add(edge[0]);
        }

        color = new HashMap<>();
        for (int i = 1; i <= n; i++){
            if (!color.containsKey(i) && !dfs(i, 0)){
                return false;
            }
        }
        return true;

    }
    public boolean dfs(int node, int c){
        if (color.containsKey(node)){
            return color.get(node) == c;
        }
        color.put(node,c);
        for (int nei : graph[node]){
            if (!dfs(nei, c ^ 1)){
                return false;
            }
        }
        return true;
    }
}

间隔,查看是否有交叉

florenzliu commented 3 years ago

Explanation

Python

class Solution:
    def possibleBipartition(self, n: int, dislikes: List[List[int]]) -> bool:
        d = defaultdict(list)
        for a, b in dislikes:
            d[a].append(b)
            d[b].append(a)

        color = [0 for i in range(n+1)]
        for i in range(1, n+1):
            if color[i] == 0:
                color[i] = 1
                queue = [i]
                while queue:
                    curr = queue.pop(0)
                    for num in d[curr]:
                        if color[num] == color[curr]:
                            return False
                        if color[num] == 0:
                            color[num] = -color[curr]
                            queue.append(num)
        return True

Complexity:

zliu1413 commented 3 years ago

from collections import deque class Solution: def isBipartite(self, graph: List[List[int]]) -> bool: n = len(graph) colors = [0] * n for i in range(n): if colors[i] == 0: colors[i] = 1 q = deque([i]) while q: u = q.popleft() neiColor = 1 if colors[u] == 2 else 2 for v in graph[u]: if colors[v] == 0: colors[v] = neiColor q.append(v) elif colors[v] != neiColor: return False return True

time: O(V+E) space: O(V)

laofuWF commented 3 years ago
# build a graph (2-way)
# paint node by relation with 2 colors using dfs
# return false when there's confict in painting a single node

# time: O(V + E)
# space: O(V + E)

class Solution:
    def __init__(self):
        self.NOT_COLORED = 0
        self.BLUE = 1
        self.RED = -1

    def possibleBipartition(self, n: int, dislikes: List[List[int]]) -> bool:
        if len(dislikes) == 0 or len(dislikes) == 1:
            return True

        graph = collections.defaultdict(list)
        colors = [self.NOT_COLORED for i in range(n + 1)]

        for x, y in dislikes:
            graph[x].append(y)
            graph[y].append(x)

        for i in range(1, n + 1):
            if colors[i] == self.NOT_COLORED and not self.dfs(colors, graph, i, self.BLUE):
                return False

        return True

    def dfs(self, colors, graph, node, color):
        enemies = graph.get(node)
        if not enemies:
            return True

        colors[node] = color
        enemy_color = self.RED if color == self.BLUE else self.BLUE

        for enemy in enemies:
            if colors[enemy] == color:
                return False

            if colors[enemy] == self.NOT_COLORED and (not self.dfs(colors, graph, enemy, enemy_color)):
                return False

        return True
zhangzz2015 commented 3 years ago

思路

关键点

代码

C++ Code:


class Solution {
public:
    bool possibleBipartition(int n, vector<vector<int>>& dislikes) {

        vector<vector<int>> graph(n);

        // generate graph. 
        for(int i=0; i< dislikes.size(); i++)
        {
            graph[dislikes[i][0]-1].push_back(dislikes[i][1]-1);
            graph[dislikes[i][1]-1].push_back(dislikes[i][0]-1);            
        }
        vector<char> visit(n, 0);        // 0 means not visit. 1 color 2 color. 

        for(int i=0; i< n; i++)
        {
            if(visit[i]!=0)
                continue; 

            queue<int> que;                         
            que.push(i);
            visit[i] = 1; 

            while(que.size())
            {
                int isize = que.size(); 
                for(int j=0; j < isize; j++)
                {
                    int topNode = que.front(); 
                    que.pop();
                    for(int k=0; k < graph[topNode].size(); k++)
                    {
                        int nextNode = graph[topNode][k]; 
                        if(visit[nextNode]==0)
                        {
                            que.push(nextNode); 
                            visit[nextNode] = visit[topNode]==1? 2 : 1; 
                        }
                        else if(visit[nextNode] == visit[topNode])
                            return false;                         
                    }
                }                            
            }
        }
        return true;         
    }
};

复杂度分析

wangzehan123 commented 3 years ago

class Solution {
    public boolean possibleBipartition(int N, int[][] dislikes) {
        List<Set<Integer>> graph = new ArrayList<>();
        for (int i = 0; i <= N; i++) {
            graph.add(new HashSet<>());
        }
        for (int[] edge : dislikes) {
            graph.get(edge[0]).add(edge[1]);
            graph.get(edge[1]).add(edge[0]);
        }

        int[] colors = new int[N + 1];

        for (int i = 1; i < N + 1; i++){
            if (colors[i] != 0) {
                continue;
            }
            Queue<Integer> queue=new LinkedList<>();
            colors[i] = 1;
            queue.add(i);
            while (!queue.isEmpty()) {
                int curr = queue.poll();
                int color = colors[curr];
                int nextColor = color == 1 ? 2 : 1;
                for(int neighbor : graph.get(curr)) {
                    if(colors[neighbor] == 0) {
                        colors[neighbor] = nextColor;
                        queue.add(neighbor);
                    } else if (colors[neighbor] != nextColor) {                                                        
                        return false;
                    }                                                      
                }
            }
        }
        return true;
    }  
}

复杂度分析

令 n 为数组长度。

banjingking commented 3 years ago

思路

DFS color and negative color confliction solution if color the neighbor with -color, if conflict, return false.

代码

class Solution {
public boolean possibleBipartition(int N, int[][] dislikes) {
    // Ask whether dislikes could be null
    if (N <= 2) return true;
    List<Integer>[] adj = new ArrayList[N+1];
    for (int i = 1; i <= N; i++) {
        adj[i] = new ArrayList<>();
    }
    for (int[] edge : dislikes) {
        adj[edge[0]].add(edge[1]);
        adj[edge[1]].add(edge[0]);
    }
    int[] colors = new int[N+1];
    for (int i = 1; i <= N; i++) {
        if (colors[i] == 0) {
            if (!dfs(i, adj, colors, 1)) {
                return false;
            }
        }
    }
    return true;
}

private boolean dfs(int node, List<Integer>[] adj, int[] colors, int color) {
    if (colors[node] != 0) {
        return colors[node] == color;
    }
    colors[node] = color;
    for (int neighbor : adj[node]) {
        if (!dfs(neighbor, adj, colors, -color)) {
            return false;
        }
    }
    return true;
}
}

Time complexity

空间复杂度: O(N+E)

时间复杂度: O(N+E)

ghost commented 3 years ago

题目

  1. Possible Bipartition

思路

Build graph and use the colors array to represent two groups.

代码


class Solution:
    def possibleBipartition(self, n: int, dislikes: List[List[int]]) -> bool:
        g = collections.defaultdict(list)

        for d in dislikes:
            g[d[0]].append(d[1])
            g[d[1]].append(d[0])

        colors = [0] * (n+1)
        for i in range(1,n+1):
            if colors[i] != 0: continue

            colors[i] = 1
            queue= collections.deque([i])

            while(queue):
                t = queue.popleft()

                for people in g[t]:
                    if colors[people] == colors[t]: return False
                    if colors[people] == 0:
                        colors[people] = -colors[t]
                        queue.append(people)

        return True

复杂度

Space: O(V+E) Time: O(V+E)

mannnn6 commented 3 years ago

代码

public class Solution {
    public boolean possibleBipartition(int N, int[][] dislikes) {
        N++;
        int[] flags = new int[N];
        List<List<Integer>> adjacency = new ArrayList<>();
        for (int i = 0; i < N; i++) {
            adjacency.add(new ArrayList<>());
        }
        for (int[] dislike : dislikes) {
            adjacency.get(dislike[0]).add(dislike[1]);
            adjacency.get(dislike[1]).add(dislike[0]);
        }
        for (int i = 1; i < N; i++) {
            if (flags[i] == 0 && !dfs(adjacency, flags, i, 1)) return false;
        }
        return true;
    }

    private boolean dfs(List<List<Integer>> adjacency, int[] flags, int v, int color) {
        if (flags[v] != 0)
            return flags[v] == color;
        flags[v] = color;
        for (int j : adjacency.get(v)) {
            if (!dfs(adjacency, flags, j, -color))
                return false;
        }
        return true;
    }
}

复杂度

空间复杂度: O(N+M) 时间复杂度: O(N+M)

JinMing-Gu commented 3 years ago
class Solution {
private:
    static constexpr int UNCOLORED = 0;
    static constexpr int RED = 1;
    static constexpr int GREEN = 2;
    vector<int> color;
    bool valid;

public:
    void dfs(int node, int c, const vector<vector<int>>& graph) {
        color[node] = c;
        int cNei = (c == RED ? GREEN : RED);
        for (int neighbor: graph[node]) {
            if (color[neighbor] == UNCOLORED) {
                dfs(neighbor, cNei, graph);
                if (!valid) {
                    return;
                }
            }
            else if (color[neighbor] != cNei) {
                valid = false;
                return;
            }
        }
    }

    bool isBipartite(vector<vector<int>>& graph) {
        int n = graph.size();
        valid = true;
        color.assign(n, UNCOLORED);
        for (int i = 0; i < n && valid; ++i) {
            if (color[i] == UNCOLORED) {
                dfs(i, RED, graph);
            }
        }
        return valid;
    }
};
ZacheryCao commented 3 years ago

Solution

DFS. Check whether current node's neighbor has same label as current node

Code(python)

from collections import defaultdict
class Solution:
    def possibleBipartition(self, n: int, dislikes: List[List[int]]) -> bool:
        def dfs(person, l):
            label[person] = l
            if person in G:
                for other in G[person]:
                    if label[other] == l:
                        return False
                    if not label[other] and not dfs(other, -l):
                        return False
            return True

        G = defaultdict(list)
        for i, j in dislikes:
            G[i].append(j)
            G[j].append(i)
        label = [0] * (n+1)
        for i in range(1, n+1):
            if not label[i] and not dfs(i, 1):
                return False
        return True

Complexity:

Time: O(E+V): E: number of edges; N:number of nodes. We need to go through all edges to build a graph. Then we need to check each node with O(N).

Space: O(E+V): O(E) for the graph. O(N) for the node's label.

taojin1992 commented 3 years ago

Understand:

ai < bi
All the pairs of dislikes are unique. -> bi-directional dislike
a person cannot dislike her/himself

Plan:

adjacent matrix, 1 dislike each other, 0 no dislike

coloring: hashmap/array to store the grouping of each person
0: default
1/-1: two groups

Alg:

- put the first unvisited person in group 1

dfs:
    color the person
    for each of his haters:
        if see one hater in same group, then return false (violation)
        if hater not assigned, call dfs (flip the color)

main body: 
for each person:
    if not visited, check on dfs, if !dfs, then return false

return true

Evaluate:

Adjacent matrix:
Time: O(dislikes.length) + O(V + E) = O(dislikes.length) + O(V + V^2) = O(dislikes.length) + O(n*n), E here is V^2
Space: graph O(V*V), visited O(V), dfs stack O(V), V = n

Adjacent list:
Time: O(n) + O(dislikes.length) + O(V + E), V = n, E = dislikes.length,
O(n + dislikes.length)
Space: O(V + E) for graph, O(V) for visited, dfs stack O(V)

Code:

class Solution {
    // adjacent list
    public boolean possibleBipartition(int n, int[][] dislikes) {
        Set<Integer>[] graph = new HashSet[n]; // syntax!
        // build graph
        for (int i = 0; i < n; i++) {
            graph[i] = new HashSet<>();
        }
        for (int[] dislike : dislikes) {
            int a = dislike[0], b = dislike[1];
            graph[a - 1].add(b - 1); // note: off by 1 here
            graph[b - 1].add(a - 1);
        }
        int color = 1;
        int[] visited = new int[n];
        // check
        for (int person = 0; person < n; person++) {
            if (visited[person] == 0 && !dfs(graph, visited, color, person, n)) {
                return false;
            }
        }
        return true;
    }

    private boolean dfs(Set<Integer>[] graph, int[] visited, int color, int person, int n) {
        visited[person] = color;
        // only for that set, no need for 0 ~ n-1
        for (int i : graph[person]) {
            if (graph[person].contains(i)) { // hater check
                if (visited[i] == color) {
                    return false;
                }
                else if (visited[i] == 0 && !dfs(graph, visited, -color, i, n)) {
                    return false;
                }
            }
        }
        return true;
    }

    // adjacent matrix
/*
    public boolean possibleBipartition1(int n, int[][] dislikes) {
        int[] visited = new int[n];
        int[][] graph = new int[n][n];
        // build graph
        for (int[] dislike : dislikes) {
            graph[dislike[0] - 1][dislike[1] - 1] = 1;
            graph[dislike[1] - 1][dislike[0] - 1] = 1;
        }
        int color = 1;
        for (int person = 0; person < n; person++) {
            if (visited[person] == 0 && !dfs(graph, visited, person, color, n)) {
                return false;
            }
        }
        return true;
    }

    private boolean dfs(int[][] graph, int[] visited, int person, int color, int n) 
    {
        visited[person] = color;
        for (int i = 0; i < n; i++) {
            if (graph[person][i] == 1) {
                if (visited[i] == color) {
                    return false;
                }
                else if (visited[i] == 0 && !dfs(graph, visited, i, -color, n)) {
                    return false;
                }
            }
        }
        return true;
    }
*/    

// adjacent matrix with notes
/*      
    public boolean possibleBipartition(int n, int[][] dislikes) {
        int[][] graph = new int[n][n];
        for (int[] dislike : dislikes) {
            int a = dislike[0], b = dislike[1];
            graph[a - 1][b - 1] = 1;
            graph[b - 1][a - 1] = 1;
        }
        int color = 1;

        // for each unvisited person, go as deep as possible 
        int[] visited = new int[n];

        for (int i = 0; i < n; i++) { 
            if (visited[i] == 0 && !dfs(visited, graph, i, color, n)) {
                return false;
            }
        }
        return true;

    }

    // person here starts with 0
    // we only care about the hater, non-haters can be together or not, they do not matter
    // e.g. if person here is Mr.nice, mark it as current color, return true directly 
    // go as deep as possible for one person in this function
    private boolean dfs(int[] visited, int[][] graph, int person, int color, int n) {
        // color the person
        visited[person] = color;
        // iterate everyone
        for (int i = 0; i < n; i++) {

            // dislike each other
            if (graph[person][i] == 1) { // self-self no hate, guarantee i != person.         
                // we already assign the hater's group
                if (visited[i] == color) {
                    return false;
                } else if (visited[i] == 0 && !dfs(visited, graph, i, -color, n)) { // we haven't assigned the hater, give a different color, keep on coloring as many as possible, need to put dfs in if statement
                    return false;
                }
            }
        }
        return true; // no collision found
    }

*/
}
nonevsnull commented 3 years ago

思路

Failed

AC

代码

class Solution {
    public boolean possibleBipartition(int n, int[][] dislikes) {
        int[][] graph = new int[n][n];

        for(int i = 0;i < dislikes.length;i++){
            int row = dislikes[i][0] - 1;
            int col = dislikes[i][1] - 1;
            graph[row][col] = 1;
            graph[col][row] = 1;
        }
        int[] visited = new int[n];
        for(int i = 0;i < n;i++){
            if(visited[i] == 0 && !dfs(graph, i, visited, 1)){
                return false;
            }
        }
        return true;
    }

    public boolean dfs(int[][] graph, int point, int[] visited, int group){
        visited[point] = group;
        //all edges
        for(int i = 0;i < graph[point].length;i++){
            if(graph[point][i] != 0){
                if(visited[i] != 0){
                    if(visited[i] == group){
                        return false;
                    }
                } else {
                    if(!dfs(graph, i, visited, -group)){
                        return false;
                    }
                }
            }
        }
        return true;
    }
}

复杂度

time: O(V+E),每个边在建图时都遍历到了,每个点在dfs时都遍历到了。 space: O(V),建图需要array, O(N),以及递归需要的空间O(N).递归最深入的情况,比如1-2, 2-3, 3-4, 4-5, 5-6,就有V层了;

wangyifan2018 commented 3 years ago
class Solution(object):
    def possibleBipartition(self, N, dislikes):
        graph = collections.defaultdict(list)
        for u, v in dislikes:
            graph[u].append(v)
            graph[v].append(u)

        color = {}
        def dfs(node, c = 0):
            if node in color:
                return color[node] == c
            color[node] = c
            return all(dfs(nei, c ^ 1) for nei in graph[node])

        return all(dfs(node)
                   for node in range(1, N+1)
                   if node not in color)
skinnyh commented 3 years ago

Note

Solution

class Solution:
    def possibleBipartition(self, n: int, dislikes: List[List[int]]) -> bool:
        adj_list = defaultdict(list)
        for d in dislikes:
            adj_list[d[0]].append(d[1])
            adj_list[d[1]].append(d[0])
        colors = [0] * (n + 1)
        for i in range(1, n + 1):
            if colors[i] != 0:
                continue
            colors[i] = 1
            q = deque([i])
            while(q):
                j = q.popleft()
                # for all j's dislikes
                for k in adj_list[j]:
                    if colors[k] == colors[j]:
                        return False
                    if colors[k] == 0:
                        colors[k] = -colors[j]
                        q.append(k)
        return True

Time complexity: O(V + E) V is the vertices and E is the edges.

Space complexity: O(V + E)

shamworld commented 3 years ago

思路

不懂,抄下

var possibleBipartition = function(n, dislikes) {
     let graph = [...Array(n + 1)].map(() => Array()), // 动态创建二维数组
      colors = Array(n + 1).fill(-1)

    // build the undirected graph
    for (const d of dislikes) {
        graph[d[0]].push(d[1])
        graph[d[1]].push(d[0])
    }

    const dfs = (cur, color = 0) => {
        colors[cur] = color
        for (const nxt of graph[cur]) {
        if (colors[nxt] !== -1 && colors[nxt] === color) return false // conflict
        if (colors[nxt] === -1 && !dfs(nxt, color ^ 1))  return false;
        }
        return true
    };

    for (let i = 0; i < n; ++i)
        if (colors[i] === -1 && !dfs(i, 0)) return false

    return true
};
sxr000511 commented 3 years ago

class Solution: def dfs(self, graph, colors, i, color, N): colors[i] = color for j in range(N):

dislike eachother

        if graph[i][j] == 1:
            if colors[j] == color:
                return False
            if colors[j] == 0 and not self.dfs(graph, colors, j, -1 * color, N):
                return False
    return True

def possibleBipartition(self, N: int, dislikes: List[List[int]]) -> bool:
    graph = [[0] * N for i in range(N)]
    colors = [0] * N
    for a, b in dislikes:
        graph[a - 1][b - 1] = 1
        graph[b - 1][a - 1] = 1
    for i in range(N):
        if colors[i] == 0 and not self.dfs(graph, colors, i, 1, N):
            return False
    return True
Leonalhq commented 3 years ago

思路

居然之前学校的例子,标记颜色 + 建立双向图,临近的颜色不能一样。其他的就抄bfs

解法

''''

class Solution:

def possibleBipartition(self, n: int, dislikes: List[List[int]]) -> bool:

​ if not dislikes:

​ return True

​ queue,visited = deque(),{}

​ graph = defaultdict(set)

​ for f,t in dislikes:

​ graph[f].add(t)

​ graph[t].add(f)

​ for i in range(1,n+1):

​ if i not in visited:

​ queue.append(i)

​ visited[i] = 0 if i-1 in visited and visited[i-1]==1 else 1

​ while queue:

​ curr = queue.popleft()

​ for nbr in graph[curr]:

​ if nbr not in visited:

​ queue.append(nbr)

​ visited[nbr] = 1 if visited[curr]==0 else 0

​ else:

​ if visited[nbr] == visited[curr]:

​ return False

​ return True

''''

复杂度

O(N+E) for both

V-Enzo commented 3 years ago

思路:

  1. 染色法+dfs
  2. dfs是针对能否染色的问题。

    class Solution {
    public:
    bool dfs(vector<vector<int>>& graph, vector<int>& colors, int pos, int color){
        colors[pos] = color;
        for(auto neighbor:graph[pos]){
            if(colors[neighbor] == color){
                return false;
            }
            if(colors[neighbor]==0 && !dfs(graph, colors, neighbor, -1*color)){
                return false;
            }
        }
        return true;
    }
    
    bool isBipartite(vector<vector<int>>& graph) {
        int n = graph.size();
        vector<int> colors(n, 0);  
        for(int i=0; i<graph.size(); i++){
            if(colors[i]==0 &&!dfs(graph, colors, i, 1)){
                return false;
            }
        }
        return true;
    }
    };

    Complexity

    Time:O(N+E) Space:O(N+E)

hewenyi666 commented 3 years ago

题目名称

886. 可能的二分法

题目链接

https://leetcode-cn.com/problems/possible-bipartition/

题目思路

对于每个连通的部分,只需试着用两种颜色对它进行着色,就可以检查它是否是二分的。将任一结点涂成红色,然后将它的所有邻居都涂成蓝色,然后将所有的邻居的邻居都涂成红色,以此类推

code for Python3

class Solution(object):
    def possibleBipartition(self, N, dislikes):
        graph = collections.defaultdict(list)
        for u, v in dislikes:
            graph[u].append(v)
            graph[v].append(u)

        color = {}
        def dfs(node, c = 0):
            if node in color:
                return color[node] == c
            color[node] = c
            return all(dfs(nei, c ^ 1) for nei in graph[node])

        return all(dfs(node)
                   for node in range(1, N+1)
                   if node not in color)

复杂度分析

flame0409 commented 3 years ago

思路:

图类型的题,如何深度遍历是关键。

这道题在遍历的基础上加了一个分组信息,分组信息存放在visited中。

class Solution {
    public boolean possibleBipartition(int n, int[][] dislikes) {
        int[][] martix = new int[n][n];
        for(int i = 0;i < dislikes.length;i++){
            martix[dislikes[i][0] - 1][dislikes[i][1] - 1] = 1;
            martix[dislikes[i][1] - 1][dislikes[i][0] - 1] = 1;
        }
        int[] visited = new int[n];                        
        for(int i = 0; i < n ; i++){
            if(visited[i] == 0 && !dfs(martix, i , visited, 1))
            return false;
        }
        return true;
    }

    public boolean dfs(int[][] martix, int point, int[] visited, int group){
        visited[point] = group;
        for(int i = 0; i < martix[0].length; i++){
            //不同组
            if(martix[point][i] != 0){
                if(visited[i] != 0){
                    if(visited[i] == group){
                        return false;
                    }
                }
                else{
                    if(!dfs(martix, i, visited, -group)){
                        return false;
                    }
                }
            }
        }
        return true;
    }
}                          

时间复杂度:O(V+E) V为节点数量,E为边数量

空间复杂度:O(V^2) 邻接矩阵占用空间为V^2

ZJP1483469269 commented 3 years ago

思路

dfs 染色

代码

class Solution {
private boolean res = true;
public boolean possibleBipartition(int N, int[][] dislikes) {
    int[][] graph = new int[N + 1][N + 1];
    for (int[] edge : dislikes) {
        graph[edge[0]][edge[1]] = 1;
        graph[edge[1]][edge[0]] = 1;
    }
    boolean[] colors = new boolean[N + 1];
    boolean[] visited = new boolean[N + 1];
    for (int i = 1; i <= N; ++i) {
        if (!visited[i]) dfs(graph, visited, colors, i);
        if (!res) return false;
    }
    return true;
}
public void dfs(int[][] graph,boolean[] visited,boolean[] colors,int start){
    visited[start]=true;
    for(int i=1;i<graph.length;i++){
        if(graph[start][i]==0) continue;
        if (!visited[i]) {
            colors[i] = !colors[start];
            dfs(graph, visited, colors, i); 
        } else if (colors[i] == colors[start]) 
            res = false;
    }

}
}

复杂度分析

时间复杂度:O(N+E) 空间复杂度:O(N+E)

yan0327 commented 3 years ago

思路: 昨天还在看西法树的讲义,当时对染色法不理解,今天就出现了。 然后自己对着染色法答案实现了一下 逻辑就是,用一个数组对图中状态进行分解,控制一个valid变量表示是否为二分图 首先遍历整个图,每次遍历图的时候判断该节点的状态。 若是未染色uncolor状态,则进行一次dfs深度搜索。【三个参数:索引,颜色,图】 dfs搜索体现为,先将颜色数组对应的索引置对应的颜色,并用一个变量表示相邻的颜色如红色 若索引中的颜色为红色,则相邻的颜色为绿色。 对该节点相邻的节点进行遍历,若存在未染色的节点,则再一次DFS,并将颜色置为前面新生成变量的颜色,然后返回 若存在染色的节点且不等于新变量的节点,则令valid为fasle,然后返回

var (
    uncolor,red,green = 0,1,-1
    color []int
    valid bool
)

func isBipartite(graph [][]int) bool {
    n := len(graph)
    valid = true
    color = make([]int,n)
    for i:=0;i<n&&valid;i++{
        if color[i] == uncolor{
            dfs(i,red,graph)
        }
    }
    return valid
}
func dfs(node int,c int, graph [][]int){
    color[node] = c
    cNei := red
     if c == red{
         cNei = green
     }
     for _,x := range graph[node]{
         if color[x] == uncolor{
             dfs(x, cNei,graph)
             if !valid{
                 return
             }
         }else if color[x] != cNei{
             valid = false
             return
         }
     }
}

时间复杂度O(n+k) 空间复杂度:O(n)

zol013 commented 3 years ago

思路: 先把dislikes用defaultdict转换成 graph, 然后用bfs或dfs 对图中节点进行二色着色, 相邻节点涂上不同颜色,如果能把图完全涂完说明可以二分。 Python 3 code:

class Solution:
    def possibleBipartition(self, n: int, dislikes: List[List[int]]) -> bool:
        # BFS method
        graph = defaultdict(list)
        for p1, p2 in dislikes:
            graph[p1].append(p2)
            graph[p2].append(p1)

        colored = {}

        for i in range(1, n + 1):
            if i not in colored:
                stack = [i]
                colored[i] = 0
                while stack:
                    node = stack.pop()
                    for neighbor in graph[node]:
                        if neighbor not in colored:
                            colored[neighbor] = colored[node] ^ 1
                            stack.append(neighbor)
                        elif colored[neighbor] == colored[node]:
                            return False
        return True

        # DFS method
        graph = defaultdict(list)
        for p1, p2 in dislikes:
            graph[p1].append(p2)
            graph[p2].append(p1)

        colored = {}

        def dfs(i, color):
            if i in colored:
                return colored[i] == color
            colored[i] = color
            for neighbor in graph[i]:
                if not dfs(neighbor, color ^ 1):
                    return False
            return True

        for node in range(1, n + 1):
            if node not in colored:
                if not dfs(node, 0):
                    return False
        return True

Time Complexity: O(N + E) Space Complexity: O(N + E)

ziyue08 commented 3 years ago
var possibleBipartition = function(n, dislikes) {
    var dfs = (index, what_color) => {
        if (need_color.has(index)){
             color[index] = what_color;
             need_color.delete(index);
             for (enermy of graph.get(index)){
                 if (!dfs(enermy, 1-what_color)) return false;
             };
             return true;
         }else{
             if (color[index] === 1-what_color) return false;
             return true;
         }
     }

    const graph = new Map();
    for ([p1,p2] of dislikes){
        if (graph.has(p1)) graph.get(p1).push(p2);
        else graph.set(p1, [p2]);
        if (graph.has(p2)) graph.get(p2).push(p1);
        else graph.set(p2, [p1]);
    };

    const dye = 1;
    let color = [];
    var need_color = new Set()
    for (let i=0; i<=n; i++){
        color.push(-1);
        need_color.add(i);
    };

    for (person of graph.keys()){
        if (need_color.has(person)){
            color[person] = dye;
            need_color.delete(person);
            for (enermy of graph.get(person)){
                if (!dfs(enermy, 1-dye)) return false;
            };
        }else{
            for (enermy of graph.get(person)){
                if (!dfs(enermy, 1-color[person])) return false;
            };
        }
    };
    return true;  
};
kidexp commented 3 years ago

thoughts

先建无向图,dfs染色, 题目如果能分为二分图,就意味着相邻的node不能是一个颜色,如果不能分为二分图就是意味着有一个node会被assign两个颜色

code

from collections import defaultdict

class Solution:
    def possibleBipartition(self, n: int, dislikes: List[List[int]]) -> bool:
        graph = defaultdict(list)
        for start, end in dislikes:
            graph[start].append(end)
            graph[end].append(start)

        def dfs(node, color):
            if node in node_color:
                if node_color[node] != color:
                    return False
                return True
            node_color[node] = color
            return (
                all(dfs(next_node, not color) for next_node in graph[node])
                if graph[node]
                else True
            )

        node_color = {}
        for node in range(1, n + 1):
            if node not in node_color:
                if not dfs(node, True):
                    return False
        return True

complexity

m 为edge的个数即dislike的长度 他的数量级可以是O(n^2)的

时间O(m)

空间O(m)

shawncvv commented 3 years ago

思路

dfs 染色

代码

Python Code

class Solution:
    def dfs(self, graph, colors, i, color, N):
        colors[i] = color
        for j in range(N):
            # dislike eachother
            if graph[i][j] == 1:
                if colors[j] == color:
                    return False
                if colors[j] == 0 and not self.dfs(graph, colors, j, -1 * color, N):
                    return False
        return True

    def possibleBipartition(self, N: int, dislikes: List[List[int]]) -> bool:
        graph = [[0] * N for i in range(N)]
        colors = [0] * N
        for a, b in dislikes:
            graph[a - 1][b - 1] = 1
            graph[b - 1][a - 1] = 1
        for i in range(N):
            if colors[i] == 0 and not self.dfs(graph, colors, i, 1, N):
                return False
        return True

复杂度

另 V 和 E 分别为图中的点和边的数目

zhangzhengNeu commented 3 years ago

思路: n个节点,联通的颜色不能相同,

public boolean isBipartite(int[][] graph) { int n = graph.length; color = new int[n]; Arrays.fill(color, UNCOLORED); for (int i = 0; i < n; ++i) { if (color[i] == UNCOLORED) { Queue queue = new LinkedList(); queue.offer(i); color[i] = RED; while (!queue.isEmpty()) { int node = queue.poll(); int cNei = color[node] == RED ? GREEN : RED; for (int neighbor : graph[node]) { if (color[neighbor] == UNCOLORED) { queue.offer(neighbor); color[neighbor] = cNei; } else if (color[neighbor] != cNei) { return false; } } } } } return true; }

JK1452470209 commented 3 years ago

思路

图的遍历 染色法

代码

class Solution {
    ArrayList<Integer>[] graph;
    Map<Integer, Integer> color;

    public boolean possibleBipartition(int N, int[][] dislikes) {
        graph = new ArrayList[N+1];
        for (int i = 1; i <= N; ++i)
            graph[i] = new ArrayList();

        for (int[] edge: dislikes) {
            graph[edge[0]].add(edge[1]);
            graph[edge[1]].add(edge[0]);
        }

        color = new HashMap();
        for (int node = 1; node <= N; ++node)
            if (!color.containsKey(node) && !dfs(node, 0))
                return false;
        return true;
    }

    public boolean dfs(int node, int c) {
        if (color.containsKey(node))
            return color.get(node) == c;
        color.put(node, c);

        for (int nei: graph[node])
            if (!dfs(nei, c ^ 1))
                return false;
        return true;
    }
}

复杂度

时间复杂度:O(E+V)

空间复杂度:O(E+V)

xieyj17 commented 3 years ago
class Solution:
    def possibleBipartition(self, n: int, dislikes: List[List[int]]) -> bool:
        if n == 1:
            return True

        if not dislikes:
            return True

        def dfs(cur, color):
            colors[cur] = color
            neighbors = graph[cur]
            for n in neighbors:
                if colors[n] == color:
                    return False
                if colors[n] == 0 and not dfs(n, -color):
                    return False
            return True

        graph = defaultdict(list)
        colors = [0]*n
        for a,b in dislikes:
            graph[a-1].append(b-1)
            graph[b-1].append(a-1)

        for i in range(n):
            if colors[i] == 0 and not dfs(i, 1):
                return False
        return True

看了答案才看懂, DFS + 着色

Time: O(V+E)

Space: O(V+E)

BlueRui commented 3 years ago

Problem 886. Possible Bipartition

Algorithm

Complexity

Code

Language: Java

public boolean possibleBipartition(int n, int[][] dislikes) {
    boolean[][] graph = new boolean[n][n];
    for (int[] d : dislikes) {
        graph[d[0] - 1][d[1] - 1] = true;
        graph[d[1] - 1][d[0] - 1] = true;
    }
    // Use an int array to represent groups.
    // 0 is not grouped, 1 and -1 represent two groups
    int[] colors = new int[n];
    for (int u = 0; u < n; u++) {
        // The loop ensures all nodes are handled when the graph is not connected
        if (colors[u] == 0 && !paint(u, 1, colors, graph)) {
            return false;
        }
    }
    return true;
}

private boolean paint(int u, int color, int[] colors, boolean[][] graph) {
    // Return if it is feasible to paint "u" to "color"
    if (colors[u] != 0) {
        // u already has a group, check if we are assign it to another group
        return colors[u] == color;
    }
    // Paint "u" with "color" (assign group), then DFS
    colors[u] = color;
    for (int v = 0; v < colors.length; v++) {
        if (graph[u][v] && !paint(v, -color, colors, graph)) {
            return false;
        }
    }
    return true;
}
QiZhongdd commented 3 years ago
class Solution {
    // 标记是否能够二分
    private boolean isTwoColorable = true;

    public boolean possibleBipartition(int N, int[][] dislikes) {
        // 首先将图构建成邻接矩阵表示
        int[][] graph = new int[N + 1][N + 1];
        for (int[] edge : dislikes) {
            graph[edge[0]][edge[1]] = 1;
            graph[edge[1]][edge[0]] = 1;
        }
        // 用来标记每一个节点的颜色,true 是一种颜色, false 是一种颜色
        boolean[] colors = new boolean[N + 1];
        // 用来标记是否访问过某一个节点
        boolean[] visited = new boolean[N + 1];

        for (int i = 1; i <= N; ++i) {
            // 如果没有访问过 i 节点,那么就从该节点开始进行深度优先搜索
            if (!visited[i]) dfs(graph, visited, colors, i);
            // 在搜索完一个连通分量后,如果发现已经不能够二分了,那么就直接返回 false
            if (!isTwoColorable) return false;
        }
        return true;
    }

    private void dfs(int[][] graph, boolean[] visited, boolean[] colors, int start) {
        // 首先标记访问过这个变量了
        visited[start] = true;
        // 然后对这个变量的邻居节点挨个访问
        for (int i = 1; i < graph.length; ++i) {
            // 如果是 0 的话,说明 start - i 之间没有相连,所以跳过就好了
            if (graph[start][i] == 0) continue;
            // 如果没有访问过,就进行访问
            if (!visited[i]) {
                colors[i] = !colors[start];     // 染成不同的颜色
                dfs(graph, visited, colors, i); // 然后再进行深度优先搜索
            } else if (colors[i] == colors[start]) 
                // 如果发现访问过 i 节点,但是 i 节点和 start 节点是一样的颜色了,
                // 那么说明图中有两个相邻节点不能染成两种颜色
                isTwoColorable = false;
        }
    }
}
yingliucreates commented 3 years ago

link:

https://leetcode.com/problems/possible-bipartition/

代码 Javascript

const possibleBipartition = function (N, dislikes) {
  const graph = [...Array(N + 1)].map(() => []);
  const visited = Array(N + 1).fill(false);
  const color = Array(N + 1).fill(0);

  for (let [u, v] of dislikes) {
    graph[u].push(v);
    graph[v].push(u);
  }

  for (let i = 1; i <= N; i++) {
    if (!colorNodes(i)) return false;
  }
  return true;

  function colorNodes(node) {
    if (visited[node]) return true;
    const currColor = new Set([1, 2]);
    for (let child of graph[node]) {
      if (color[child] === 1) currColor.delete(1);
      if (color[child] === 2) currColor.delete(2);
    }
    if (currColor.size === 0) return false;

    color[node] = Math.min(...currColor);
    visited[node] = true;

    for (let child of graph[node]) {
      if (!colorNodes(child)) return false;
    }
    return true;
  }
};

复杂度分析

time & space O(n)?

SunnyYuJF commented 3 years ago

思路

Graph+DFS 染色

代码 Python

def possibleBipartition(self, n: int, dislikes: List[List[int]]) -> bool:
        graph = collections.defaultdict(list)
        for a,b in dislikes:
            graph[a-1].append(b-1)
            graph[b-1].append(a-1)

        def dfs(node, color):
            colors[node]=color
            for dislike in graph[node]:
                if colors[dislike]==color:
                    return False
                if colors[dislike]==0 and not dfs(dislike, -color):
                    return False
            return True

        colors=[0]*n
        for i in range(n):
            if colors[i]==0 and not dfs(i,1):
                return False
        return True

复杂度分析

时间复杂度: O(V+E)
空间复杂度: O(V+E)

comst007 commented 3 years ago

886. 可能的二分


思路

图相关知识
将两个人之间的不喜欢关系转化成一张有向图。每个人是一个结点,dislikes[i] = [a, b] 表示存在 结点 ab之间存在边。问题就转换成图能否被二分,通过染色法判断图能否被二分。

代码

class Solution {
private:
    vector<vector<int>> g;
    vector<int> colors;
    bool dfs(int ii, int c){
        colors[ii] = c;
        for(auto jj: g[ii]){
            if(colors[jj]){
                if(colors[jj] == colors[ii]){
                    return false;
                }
                continue;
            }
            if(!dfs(jj, 3 - c)){
                return false;
            }
        }

        return true;
    }
public:
    bool possibleBipartition(int n, vector<vector<int>>& dislikes) {
        g.resize(n + 1);
        colors.resize(n + 1, 0);
        for(auto cur: dislikes){
            g[cur[0]].push_back(cur[1]);
            g[cur[1]].push_back(cur[0]);
        }
        for(int ii = 1; ii <= n; ++ ii){
            if(colors[ii] == 0){
                if(!dfs(ii, 1)){
                    return false;
                }
            }
        }

        return true;
    }
};

复杂度分析

n为图结点数。m为dislikes数组长度

shixinlovey1314 commented 3 years ago

Title:886. Possible Bipartition

Question Reference LeetCode

Solution

Build a Graph based on the dislikes. 2 people can be in the same group if there's no edge between them. Iterate through each person, for each person, put all the people that he dislike into a set. Then go through the set and see if any two people in the set dislike each other. Return false if that's the case.

Use 2-color method to attempt to put the people into 2 groups.

Algo:

  1. Iterate through each person, try to put that person into group 1.
  2. Find all of the people that he dislikes, if any of them already in the group 1, then we failed.
  3. Otherwise, if that perople has not been assigned group, we try to put that person into another group, and thus repeat 2.

Code

class Solution {
public:
    bool dfs(vector<vector<int>>& graph, vector<int>& group, int index, int groupId) {
        group[index] = groupId;
        for (int j = 1; j < group.size(); j++) {
            if (graph[index][j]) {
                if (group[j] == groupId)
                    return false;
                else if ((group[j] == 0) && !dfs(graph, group, j, -1 * groupId))
                    return false;
            }
        }

        return true;
    }

    bool possibleBipartition(int n, vector<vector<int>>& dislikes) {
        vector<vector<int>> graph(n+1, vector<int>(n+1, 0));

        for (auto dislike : dislikes) {
            graph[dislike[0]][dislike[1]] = 1;
            graph[dislike[1]][dislike[0]] = 1;
        }

        vector<int> group(n+1, 0);

        for (int i = 1; i <= n; i++) {
            if (group[i] == 0) {
                if (!dfs(graph, group, i, 1))
                    return false;
            }
        }

        return true;
    }
};

Complexity

Time Complexity and Explanation

O(n^2): Each node may need to compare with N-1 other nodes, and we need to check all N nodes.

Space Complexity and Explanation

O(n^2): Use to store the graph

mmboxmm commented 3 years ago

思路

BFS + Coloring

代码

fun possibleBipartition(n: Int, dislikes: Array<IntArray>): Boolean {
  val graph = Array<MutableSet<Int>>(n + 1) { mutableSetOf() }
  val colors = IntArray(n + 1) { 0 }

  dislikes.forEach { d ->
    graph[d[0]].add(d[1])
    graph[d[1]].add(d[0])
  }

  for (i in 1..n) {
    if (colors[i] != 0) continue
    val queue = mutableListOf<Int>()
    queue.add(i)
    colors[i] = 1

    while (queue.isNotEmpty()) {
      val size = queue.size
      repeat(size) {
        val head = queue.removeAt(0)
        for (next in graph[head]) {
          if (colors[next] == colors[head]) return false
          if (colors[next] == 0) {
            colors[next] = -colors[head]
            queue.add(next)
          }
        }
      }
    }
  }
  return true
}
tongxw commented 3 years ago

思路

最开始想用两个setf分组。没写出来。。。 看的题解用染色法。

代码

class Solution {
    public boolean possibleBipartition(int n, int[][] dislikes) {
        List<Integer>[] people = new List[n+1];
        for (int[] dislike : dislikes) {
            int p1 = dislike[0];
            int p2 = dislike[1];
            if (people[p1] == null) {
                people[p1] = new ArrayList<>();
            }
            if (people[p2] == null) {
                people[p2] = new ArrayList<>();
            }
            people[p1].add(p2);
            people[p2].add(p1);
        }

        int[] colors = new int[n+1];
        for (int i=1; i<=n; i++) {
            if (colors[i] != 0) {
                continue;
            }

            if (!dfs(people, i, colors, 1)) {
                return false;
            }
        }

        return true;
    }

    private boolean dfs(List<Integer>[] people, int i, int[] colors, int color) {
        colors[i] = color;
        List<Integer> dislikePeople = people[i];
        for (int j : dislikePeople) {
            if (colors[j] == color) {
                return false; 
            }

            if (colors[j] == 0 && !dfs(people, j, colors, -1 * color)) {
                return false;
            }
        }

        return true;
    }
}

TC: O(v+e) SC: O(v2)