链接

一、题目描述

给定一组 n 人(编号为 1, 2, ..., n), 我们想把每个人分进任意大小的两组。每个人都可能不喜欢其他人,那么他们不应该属于同一组。

给定整数 n 和数组 dislikes ,其中 dislikes[i] = [ai, bi] ,表示不允许将编号为 ai 和  bi的人归入同一组。当可以用这种方法将所有人分进两组时,返回 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 <= 104

  • dislikes[i].length == 2

  • 1 <= dislikes[i][j] <= n

  • ai < bi

  • dislikes 中每一组都 不同

二、实现

使用并查集解答

type UnionFind struct {
	parent []int
}

func newUnionFind(size int) UnionFind {
	uf := UnionFind{
		parent: make([]int, size),
	}
	for i := range uf.parent {
		uf.parent[i] = i
	}
	return uf
}

func (uf *UnionFind) Find(x int) int {
	if uf.parent[x] != x {
		uf.parent[x] = uf.Find(uf.parent[x])
	}
	return uf.parent[x]
}

func (uf *UnionFind) Union(x, y int) {
	rootx := uf.Find(x)
	rooty := uf.Find(y)
	if rootx == rooty {
		return
	}
	if rootx < rooty {
		uf.parent[rooty] = rootx
	} else {
		uf.parent[rootx] = rooty
	}
}

func (uf *UnionFind) isConnected(x, y int) bool {
	return uf.Find(x) == uf.Find(y)
}

func possibleBipartition(n int, dislikes [][]int) bool {
	// 1. groups[i] 表示第i个人的讨厌组
	groups := make([][]int, n)
	for _, dislike := range dislikes {
		// 转化为index - 1
		x, y := dislike[0]-1, dislike[1]-1
		groups[x] = append(groups[x], y)
		groups[y] = append(groups[y], x)
	}
	// 2. 使用并查集检查连接性
	uf := newUnionFind(n)
	for x, group := range groups {
		for _, y := range group {
			// 讨厌组进行并查集合并
			uf.Union(group[0], y)
			// 如果讨厌组和当前值同组,则说明你不可行
			if uf.isConnected(x, y) {
				return false
			}
		}
	}
	return true
}