Open azl397985856 opened 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;
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
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
基于图的染色算法来做, 试着将一组node染成红色, 另一组染成蓝色, 如果遍历完没冲突, 就返回true, 否则返回false.
基于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;
}
};
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;
}
}
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
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;
};
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)
bfs二分法(参考785题解思路)
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长度
class Solution: def possibleBipartition(self, N, dislikes):
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;
思路: 染色法求解二分图
复杂度分析:
代码(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;
}
};
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;
}
}
用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)
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;
}
}
间隔,查看是否有交叉
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:
O(V+E)
O(V+E)
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)
# 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
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;
}
};
复杂度分析
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 为数组长度。
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;
}
}
空间复杂度: O(N+E)
时间复杂度: O(N+E)
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)
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)
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;
}
};
DFS. Check whether current node's neighbor has same label as current node
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
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.
ai < bi
All the pairs of dislikes are unique. -> bi-directional dislike
a person cannot dislike her/himself
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
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)
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
}
*/
}
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层了;
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)
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)
不懂,抄下
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
};
class Solution: def dfs(self, graph, colors, i, color, N): colors[i] = color for j in range(N):
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
居然之前学校的例子,标记颜色 + 建立双向图,临近的颜色不能一样。其他的就抄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
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;
}
};
Time:O(N+E) Space:O(N+E)
886. 可能的二分法
https://leetcode-cn.com/problems/possible-bipartition/
对于每个连通的部分,只需试着用两种颜色对它进行着色,就可以检查它是否是二分的。将任一结点涂成红色,然后将它的所有邻居都涂成蓝色,然后将所有的邻居的邻居都涂成红色,以此类推
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)
思路:
图类型的题,如何深度遍历是关键。
这道题在遍历的基础上加了一个分组信息,分组信息存放在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
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)
思路: 昨天还在看西法树的讲义,当时对染色法不理解,今天就出现了。 然后自己对着染色法答案实现了一下 逻辑就是,用一个数组对图中状态进行分解,控制一个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)
思路: 先把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)
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;
};
先建无向图,dfs染色, 题目如果能分为二分图,就意味着相邻的node不能是一个颜色,如果不能分为二分图就是意味着有一个node会被assign两个颜色
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
m 为edge的个数即dislike的长度 他的数量级可以是O(n^2)的
时间O(m)
空间O(m)
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 分别为图中的点和边的数目
思路: 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
思路
图的遍历 染色法
代码
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)
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)
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;
}
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;
}
}
}
https://leetcode.com/problems/possible-bipartition/
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)?
Graph+DFS 染色
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)
图相关知识
将两个人之间的不喜欢关系转化成一张有向图。每个人是一个结点,dislikes[i] = [a, b]
表示存在 结点 a
和b
之间存在边。问题就转换成图能否被二分,通过染色法判断图能否被二分。
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
数组长度
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:
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;
}
};
O(n^2): Each node may need to compare with N-1 other nodes, and we need to check all N nodes.
O(n^2): Use to store the graph
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
}
最开始想用两个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)
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