leetcode t886 可能的二分法
t886 可能的二分法
1. 题目
给定一组 n 人(编号为 1, 2, ..., n), 我们想把每个人分进任意大小的两组。每个人都可能不喜欢其他人,那么他们不应该属于同一组。
给定整数 n 和数组 dislikes ,其中 dislikes[i] = [ai, bi] ,表示不允许将编号为 ai 和 bi的人归入同一组。当可以用这种方法将所有人分进两组时,返回 true;否则返回 false
2. 分析
我们可以[ai,bi]看作是图的一条边。这样一来dislikes数组就变成一个边的集合,里面的点都是属于[1 , n]范围中。
如:
dislikes = [ [ 1,2 ], [ 2,3 ], [ 1,3 ] ]
可以转换成如下的图

转换成图了之后我们就很容易想到答案的处理方式了。
我们接下来,手腕一个用例来确定求解过程。
用例一:
n = 4, dislikes = [[1,2],[1,3],[2,4]]

经过上图,我们可以发现,当两个点相连的时候我们不能把他们涂成同一个颜色,一次我们可以从起点出发,逐层遍历,按层数的奇偶性来确定每一层的颜色。
值得注意的是,每一个点都只能有一种颜色。也就是说,像是第一个图中,如果我们选择节点1出发,那么将它涂成红色,按照我们的规则,
(1)节点2、3就应该都是绿色。
(2)但是节点3和节点2之间存在一条边,根据相邻的点颜色不能相同可知,节点2和节点3的颜色应该不同。
因此,这个图不能被分成一个可能的二分图。
而从上述的思路中,我们提到了逐层遍历,很显然,可以使用BFS实现该算法。
至于判断一个节点是否存在多个颜色,我们可以使用哈希表(或者长度为n的数组)来存放当前元素的颜色,注意有三种状态:没有颜色,红色,绿色。
如果一个节点没有颜色,那么无论他是被红色节点遍历到还是被绿色节点遍历到,我们我们直接把颜色取反即可。
而对于有颜色的节点,我们只需要判断现在节点的颜色,是否与我们根据推断出来的节点颜色相同即可。如果相同,那么继续遍历,如果不同,那么说明不存在,return false;
3. 代码
class Solution {
Map<Integer,Integer> map;//index-color
List<Integer>[] lists;
public boolean possibleBipartition(int n, int[][] dl) {
map = new HashMap<>();
lists = new List[n+1];
for(int i = 1;i<=n;i++) lists[i]=new ArrayList<>();
for(int i = 0;i<dl.length;i++){
int[] e = dl[i];
lists[e[0]].add(e[1]);
lists[e[1]].add(e[0]);
}
for(int i = 1;i<=n;i++){
if(map.get(i)==null){
if(bfs(i)){
continue;
}
else{
return false;
}
}
else{
continue;
}
}
return true;
}
public boolean bfs(int index){
Deque<Integer>[] qs=new Deque[2];
qs[0] = new ArrayDeque<Integer>();
qs[1] = new ArrayDeque<Integer>();
Deque<Integer> cur = qs[0];
Deque<Integer> next = qs[1];
map.put(index,1);
cur.offer(index);
while(cur.size()!=0){
while(cur.size()!=0){
int idx = cur.poll();
for(int i = 0;i<lists[idx].size();i++){
if(map.get(lists[idx].get(i))==null){
map.put(lists[idx].get(i),3-map.get(idx));
next.offer(lists[idx].get(i));
}
else if(map.get(lists[idx].get(i))==map.get(idx)){
return false;
}
}
}
cur = (cur==qs[0])?qs[1]:qs[0];
next = (next==qs[0])?qs[1]:qs[0];
}
return true;
}
}
浙公网安备 33010602011771号