leetcode
leetcode 801 ~ 850
可能的二分法

可能的二分法

难度:

标签:

题目描述

代码结果

运行时间: 72 ms, 内存: 21.7 MB


/*
思路:
使用 Java Stream API 解决该问题,我们仍然遵循二分图检测的思路。

具体步骤:
1. 构建图的数据结构,这里我们使用 Map<Integer, List<Integer>> 来表示邻接表。
2. 使用 Stream API 进行图的构建和处理。
3. 使用递归的方式实现 DFS 并检查冲突。
*/

import java.util.*;
import java.util.stream.*;

public class Solution {
    public boolean possibleBipartition(int n, int[][] dislikes) {
        Map<Integer, List<Integer>> graph = IntStream.rangeClosed(1, n)
                .boxed()
                .collect(Collectors.toMap(i -> i, i -> new ArrayList<>()));
        Arrays.stream(dislikes).forEach(dislike -> {
            graph.get(dislike[0]).add(dislike[1]);
            graph.get(dislike[1]).add(dislike[0]);
        });
        int[] color = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            if (color[i] == 0 && !dfs(graph, color, i, 1)) {
                return false;
            }
        }
        return true;
    }

    private boolean dfs(Map<Integer, List<Integer>> graph, int[] color, int node, int c) {
        color[node] = c;
        for (int neighbor : graph.get(node)) {
            if (color[neighbor] == 0) {
                if (!dfs(graph, color, neighbor, -c)) {
                    return false;
                }
            } else if (color[neighbor] == c) {
                return false;
            }
        }
        return true;
    }
}

解释

方法:

该题解采用了图的深度优先搜索(DFS)算法来解决问题。首先,将给定的不喜欢关系转化为一个图的邻接表表示,其中每个节点代表一个人,每条边代表两个人之间的不喜欢关系。然后,尝试将图分为两个不相交的子集(即两个组),使得每个组内的人都不互相不喜欢。为此,我们使用DFS遍历图,同时用两个数组 'left' 和 'right' 分别记录每个人是否属于左组或右组。在遍历过程中,如果遇到一个已经访问过的节点,我们检查它是否已经被分配到了正确的组中;如果遇到一个未访问过的节点,我们将其分配到当前组的对立组中,并继续DFS遍历其邻居。如果在任何时候,我们发现无法将一个节点分配到一个组中而不违反不喜欢关系,我们返回 false。如果整个图都被成功地遍历并分组,我们返回 true。

时间复杂度:

O(V + E) 或 O(n + dislikes.length)

空间复杂度:

O(V + E) 或 O(n + dislikes.length)

代码细节讲解

🦆
在DFS中,你是如何决定将节点分配到左组还是右组的?这种决定有没有特定的规则或条件?
在DFS过程中,节点的分组基于其父节点的分组情况来决定。具体的规则是:如果当前节点(我们尝试分配的节点)是从另一个已分组的节点访问到的,那么它应当被分配到与父节点相反的组中。这是因为题目要求每个组内的成员不互相不喜欢,所以如果父节点在左组,当前节点就应该分到右组,反之亦然。这种分组策略是为了确保所有不喜欢的关系都横跨两个组,而不是在同一个组内。
🦆
题解中提到,如果在遍历过程中遇到已经访问过的节点,需要检查它是否已经被分配到了正确的组中。这里的‘正确的组’是指什么?如何定义这个正确性?
在此上下文中,‘正确的组’指的是一个节点根据其与其他节点的不喜欢关系应该所在的组。具体来说,如果我们通过DFS访问到一个已经标记为访问过的节点,我们需要检查这个节点之前的分组是否与当前尝试分配的组相反。例如,如果我们当前在左组中的节点遍历到一个右组的节点,这是符合预期的;但如果发现这个节点已经在左组,那么就存在矛盾,因为它同时与左组中的一个节点有不喜欢关系,这违反了分组条件。
🦆
如果在DFS过程中发现一个节点无法被分配到任何一个组中而不违反不喜欢关系,算法会返回false。能否具体解释这种情况是如何检测出来的?
这种情况的检测通过DFS递归过程实现。在DFS中,每当我们尝试将一个节点分配到一个组时,我们会递归地尝试将与之有不喜欢关系的节点分配到相反的组。如果在此过程中,我们尝试将一个节点分配到一个组,而这个节点已经在相反的组中(由之前的DFS过程确定),则意味着无法满足分组要求(即存在同一组内的节点互相不喜欢)。这时,DFS将返回false,传递到上层递归调用中,最终结果为无法进行有效分组。

相关问题