简介:
图论是计算机科学和数学中的一个基本主题。它提供了一个强大的框架来建模实体之间的关系。LeetCode提供了各种与图相关的问题,以挑战我们的理解和问题解决能力。在本文中,我们将深入探讨问题758,“是否为二分图?”,并探索一种有效的算法来确定给定图形是否为二分图。
问题陈述:
该问题提供了一个无向图,具有n个节点,由2D数组图表示。每个节点的编号从0到n-1,并且graph [u]表示与节点u相邻的节点数组。图满足某些属性:没有自环,没有平行边,以及无向性。任务是确定图是否为二分图,其中节点可以分为两个独立的集合,使得每条边连接来自不同集合的节点。
方法:
为了解决这个问题,我们可以利用图着色的概念,并在图上执行深度优先搜索(DFS)。关键思想是为节点分配颜色,使相邻节点具有不同的颜色。如果在着色过程中遇到矛盾,我们可以得出结论,即该图不是二分图。
伪代码:
-
初始化一个数组以存储每个节点的颜色。将所有节点设置为0(未分配颜色)。
-
遍历图中的每个节点。
-
如果当前节点未分配(color [node] == 0),则从该节点开始进行DFS。
-
在DFS函数内部:
-
为当前节点分配颜色(1或-1)。
-
遍历相邻节点。
-
如果相邻节点未分配,则使用相反的颜色递归调用DFS函数。
-
如果相邻节点具有与当前节点相同的颜色,则返回false(不是二分图)。
-
如果DFS函数在没有矛盾的情况下完成,则返回true(二分图)。
实现:
class Solution:
def isBipartite(self, graph: List[List[int]]) -> bool:
colors = [0] * len(graph)
def dfs(node, color):
colors[node] = color
for neighbor in graph[node]:
if colors[neighbor] == color:
return False
if colors[neighbor] == 0 and not dfs(neighbor, -color):
return False
return True
for i in range(len(graph)):
if colors[i] == 0 and not dfs(i, 1):
return False
return True
复杂度分析:
- 时间复杂度:算法一次访问每个节点并探索其邻居,导致时间复杂度为O(V + E),其中V是图中的顶点数,E是边数。
- 空间复杂度:空间复杂度为O(V),其中V是顶点数。这是必需的,以存储每个节点的颜色。
解决方案
Python
class Solution:
def isBipartite(self, graph):
n = len(graph)
colors = [0] * n
for i in range(n):
if colors[i] == 0:
if not self.dfs(graph, colors, i, 1):
return False
return True
def dfs(self, graph, colors, node, color):
if colors[node] != 0:
return colors[node] == color
colors[node] = color
for neighbor in graph[node]:
if not self.dfs(graph, colors, neighbor, -color):
return False
return True
解释:
isBipartite
函数检查给定的图是否为二分图。dfs
函数在图上执行深度优先搜索(DFS),为节点分配颜色并检查矛盾。
在isBipartite
函数中:
n
变量表示图中的节点数。colors
列表初始化为零,将用于跟踪每个节点的颜色分配。- 函数使用for循环遍历图中的每个节点。
- 对于每个未访问的节点(当
colors [i] == 0
时),它调用dfs
函数从该节点开始执行DFS。 - 如果在任何迭代期间
dfs
函数返回False,表示着色中存在矛盾,则该函数立即返回False。 - 如果for循环完成而没有任何矛盾,则该函数返回True,表示该图为二分图。
在dfs
函数中:
graph
参数表示输入图。colors
参数是跟踪每个节点的颜色分配的列表。node
参数是正在处理的当前节点。color
参数是分配给当前节点的颜色。- 该函数首先检查当前节点的颜色是否已分配(当
colors [node]!= 0
时)。 - 如果颜色已分配,则如果分配的颜色与当前颜色匹配,则返回True,否则返回False。
- 如果颜色未分配,则将当前颜色分配给节点(
colors [node] = color
)。 - 然后,该函数对当前节点的每个邻居进行递归调用,传递相反的颜色(
-color
)。 - 如果任何递归调用返回False,表示着色中存在矛盾,则该函数返回False。
- 如果所有递归调用完成而没有任何矛盾,则该函数返回True。
Java
class Solution {
public boolean isBipartite(int[][] graph) {
int n = graph.length;
int[] colors = new int[n];
for (int i = 0; i < n; i++) {
if (colors[i] == 0 && !dfs(graph, colors, i, 1)) {
return false;
}
}
return true;
}
private boolean dfs(int[][] graph, int[] colors, int node, int color) {
if (colors[node] != 0) {
return colors[node] == color;
}
colors[node] = color;
for (int neighbor : graph[node]) {
if (!dfs(graph, colors, neighbor, -color)) {
return false;
}
}
return true;
}
}
C++
class Solution {
public:
bool isBipartite(vector<vector<int>>& graph) {
int n = graph.size();
vector<int> colors(n, 0);
for (int i = 0; i < n; i++) {
if (colors[i] == 0 && !dfs(graph, colors, i, 1)) {
return false;
}
}
return true;
}
private:
bool dfs(vector<vector<int>>& graph, vector<int>& colors, int node, int color) {
if (colors[node] != 0) {
return colors[node] == color;
}
colors[node] = color;
for (int neighbor : graph[node]) {
if (!dfs(graph, colors, neighbor, -color)) {
return false;
}
}
return true;
}
};
结论:
在本文中,我们探讨了LeetCode问题758,“是否为二分图?”,并提出了使用图着色和深度优先搜索的有效解决方案。通过利用二分性原理,我们可以确定给定的图是否可以分为两个独立的集合。理解图论和算法对于解决与图相关的问题至关重要,这个问题是应用这些概念的有价值的练习。
译自:https://medium.com/@_monitsharma/daily-leetcode-problems-problem-785-is-graph-bipartite-9e289095f576
评论(0)