886. Possible Bipartition

115 阅读1分钟

image.png

方法:二部图染色

根据输入的数组建图,其中dislike的pair,表示图中的一个edge。

问题转化为,可否把图的节点分为两个集合,其中集合内部的节点在图中不相邻。

image.png

  • To solve this problem, we can start a BFS traversal over the graph of people and start assigning the colors.
  • We can assign RED to the starting node. The color BLUE should then be assigned to all of the neighbors. Neighbors of BLUE nodes should have the color RED, and so on (keep alternating colors between neighbors).
  • Let's use 0 for RED and 1 for BLUE. To flip the colors, we can use the formula 1 - color
  • 如果发现邻居颜色相同,则有冲突,说明无法被分成两个集合。
  • There can be multiple connected components in the graph(多个联通图). We need to visit all of them to make sure we visit every node.

image.png

class Solution {
    public boolean possibleBipartition(int n, int[][] dislikes) {
        // 构建邻居列表
        Map<Integer, List<Integer>> adj = new HashMap<>();
        for (int[] arr : dislikes) {
            if (!adj.containsKey(arr[0])) {
                adj.put(arr[0], new ArrayList<>());
            }
            adj.get(arr[0]).add(arr[1]);

            if (!adj.containsKey(arr[1])) {
                adj.put(arr[1], new ArrayList<>());
            }
            adj.get(arr[1]).add(arr[0]);
        }

        // 每个节点颜色,一开始全填充-1,表示未上色
        int[] color = new int[n + 1];
        Arrays.fill(color, -1); 

        for (int i = 1; i <= n; i++) {
            // 找到一个独立的图,因为可能有多个联通图
            if (color[i] == -1) {
                // 从当前节点开始bfs染色
                if (!bfs(i, adj, color)) { 
                    return false; // 当前的图染色有冲突
                }
            }
        } 
        return true;
    }

    // bfs, 从source节点开始,给邻居染色,有冲突返回false
    public boolean bfs(int source, Map<Integer, List<Integer>> adj, int[] color) {
        Queue<Integer> queue = new LinkedList<>();
        queue.offer(source);
        color[source] = 0; // 当前节点染色

        while (!queue.isEmpty()) {
            int cur = queue.poll();
            if (!adj.containsKey(cur)) { // 没有adj列表的node
                continue;
            }
            // 遍历邻居,给他们上色
            for (int nbr : adj.get(cur)) {
                if (color[nbr] == color[cur]) {
                    return false; // 邻居颜色和当前一样,冲突
                } else if (color[nbr] == -1) {
                    color[nbr] = 1 - color[cur]; // 另一种颜色
                    queue.add(nbr);
                }
            }
        }

        return true;
    }
}