Java C++题解leetcode886可能的二分法并查集染色法
作者:AnjaVon 发布时间:2023-08-29 01:12:52
题目要求
思路一:反向点+并查集
根据题意不喜欢就不在一个组可以想到使用并查集,本题是两个集合所以对每一个节点引入一个反向点,使两者分属于不同集合,借此记录前续节点维持的不喜欢关系;
在将每个节点xxx放入组合时,同时将其反向节点x+nx+nx+n放入另一组合,然后向后遍历依次处理每个节点,同时判断相互不喜欢的两个点当前是否会被迫放入一个集合(连通),若是则无法满足题意。
下面浅学一些并查集的基本概念,然后再去实现思路——
浅学并查集(Union Find)
学习参考链接
从介绍到不断优化的整个构造推导过程,图片示例与解释很清晰。
简介:
一种树型的数据结构,用于处理一些不相交集合的合并及查询问题;
核心思想:
用一个数组表示整片森林,树的根节点唯一标识了一个集合,只要找到了某个元素的树根,就能确定它在哪个集合里;
适用场景:
用于需要反复查找某一元素属于哪个集合以进行集合合并的场景,用其他数据结构解决该类问题将造成巨大的时空开销。
基础操作:
通常包括三个函数
函数 | 功能 |
---|---|
find(x) | 查找元素xxx属于哪个集合,也就是找当前元素所在树的根节点,查找的同时进行路径压缩 |
union(a, b) | 合并元素aaa和元素bbb所属集合,根据树高合并两棵树 |
isConnected(a, b) | 判断aaa和元素bbb是否处于同一集合中,也就是判断二者根是否相同 |
Java
class Solution {
int[] p = new int[4010]; // 并查集数组,存父级节点
// 找当前节点的根
int find(int x) {
if(p[x] != x) // 非根节点
p[x] = find(p[x]); // 继续向下找根并进行路径压缩
return p[x];
}
// 连接两节点的根
void union(int a, int b) {
p[find(a)] = p[find(b)];
}
// 两节点是否连通
boolean isConnected(int a, int b) {
return find(a) == find(b);
}
public boolean possibleBipartition(int n, int[][] dislikes) {
for (int i = 1; i <= 2 * n; i++) // 节点+反向节点
p[i] = i; // 初始化并查集,指向自己
for (int[] cur : dislikes) {
int a = cur[0], b = cur[1];
if (isConnected(a, b)) // 连通,被迫在一组
return false;
// 利用反向节点维护连通关系
union(a, b + n);
union(b, a + n);
}
return true;
}
}
时间复杂度:O(n+m),其中m为dislikes的长度
空间复杂度:O(n)
C++
注意
union
会和C++中的预定义函数重名
class Solution {
public:
int p[4010]; // 并查集数组,存父级节点
// 找当前节点的根
int find(int x) {
if(p[x] != x) // 非根节点
p[x] = find(p[x]); // 继续向下找根并进行路径压缩
return p[x];
}
// 连接两节点的根
void unionn(int a, int b) {
p[find(a)] = p[find(b)];
}
// 两节点是否连通
bool isConnected(int a, int b) {
return find(a) == find(b);
}
bool possibleBipartition(int n, vector<vector<int>>& dislikes) {
for (int i = 1; i <= 2 * n; i++) // 节点+反向节点
p[i] = i; // 初始化并查集,指向自己
for (auto cur : dislikes) {
int a = cur[0], b = cur[1];
if (isConnected(a, b)) // 连通,被迫在一组
return false;
// 利用反向节点维护连通关系
unionn(a, b + n);
unionn(b, a + n);
}
return true;
}
};
时间复杂度:O(n+m)
空间复杂度:O(n)
思路二:染色法
将不喜欢数组存成一个无向图,给分属两个不同集合的点染上不同的颜色,不断更新染色并判断不喜欢关系是否能够成立;
采用链式前向星存储构建无向图,有边的两者不能是同一个颜色,用1和2表示两种不同的颜色,用000表示未染色;
定义一个
DFS(node, clr)
函数表示将节点node染成clr色
Java
class Solution {
int N = 2010, M = 2 * 10010;
int[] head = new int[N], edge = new int[M], next = new int[M];
int[] color = new int[N];
int idx = 0;;
void add(int a, int b) {
edge[idx] = b;
next[idx] = head[a];
head[a] = idx++;
}
boolean DFS(int node, int clr) {
color[node] = clr;
for (int i = head[node]; i != -1; i = next[i]) {
int j = edge[i];
// 不喜欢双方同色
if (color[j] == clr)
return false;
if (color[j] == 0 && !DFS(j, 3 - clr))
return false;
}
return true;
}
public boolean possibleBipartition(int n, int[][] dislikes) {
Arrays.fill(head, -1);
for (int[] cur : dislikes) { // 构建无向图
int a = cur[0], b = cur[1];
add(a, b);
add(b, a);
}
for (int i = 1; i <= n; i++) {
if (color[i] != 0) // 已经染过
continue;
if (!DFS(i, 1)) // 无法染色成功
return false;
}
return true;
}
}
时间复杂度:O(n+m)
空间复杂度:O(n+m)
C++
class Solution {
public:
static const int N = 2010, M = 2 * 10010;
int head[N], edge[M], next[M];
int color[N];
int idx = 0;;
void add(int a, int b) {
edge[idx] = b;
next[idx] = head[a];
head[a] = idx++;
}
bool DFS(int node, int clr) {
color[node] = clr;
for (int i = head[node]; i != -1; i = next[i]) {
int j = edge[i];
// 不喜欢双方同色
if (color[j] == clr)
return false;
if (color[j] == 0 && !DFS(j, 3 - clr))
return false;
}
return true;
}
bool possibleBipartition(int n, vector<vector<int>>& dislikes) {
memset(head, -1, sizeof(head));
for (auto cur : dislikes) { // 构建无向图
int a = cur[0], b = cur[1];
add(a, b);
add(b, a);
}
for (int i = 1; i <= n; i++) {
if (color[i] != 0) // 已经染过
continue;
if (!DFS(i, 1)) // 无法染色成功
return false;
}
return true;
}
};
时间复杂度:O(n+m)
空间复杂度:O(n+m)
来源:https://juejin.cn/post/7155034629202771998


猜你喜欢
- 要求:如下图,使用线程操作 1、实时显示当前时间 2、输入加数和被加数,自动出现结果 分析:两个问题解决的方式一致,使用子线程进
- 文档中的设置有序或无序列表是一种反应内容上下级关系或者内容相同属性的方式,与单纯的文字叙述相比,它能有效增强文档内容的条理性,突出重点。因此
- 本文实例讲述了C#实现缩放和剪裁图片的方法。分享给大家供大家参考,具体如下:using System;using System.Collec
- 写在前面jenkins作为java的好 * ,经历过单体项目时代->集群项目时代->容器集群分布式时代,使用稳定可靠,cpu友好(
- 前言缓存主要是为了提高数据的读取速度。因为服务器和应用客户端之间存在着流量的瓶颈,所以读取大容量数据时,使用缓存来直接为客户端服务,可以减少
- JPA like 模糊查询 语法格式public List<InstitutionInfo> getAllInstitution
- 发展历史Gradle 的依赖管理是一个从开始接触 Android 开发就一直伴随着我们的问题(作者是Andro
- 前言作为一个后端程序员,网络连接这块是一个绕不过的砍,当你在做服务器优化的时候,网络优化也是其中一环,那么作为网络连接中最基础的部分-TCP
- 前言这两天面试了一个物联网公司高级研发,面试题是下面这样子公司领导,部门主管,小组组长,组成员4级,假如有个 疫情预警,先通知组人员(对个人
- 前言目前互联网公司,大部分项目都是基于分布式,一个项目被拆分成几个小项目,这些小项目会分别部署在不同的计算机上面,这个叫做微服务。当一台计算
- 本文实例讲述了Java模拟死锁发生之演绎哲学家进餐问题。分享给大家供大家参考,具体如下:一 点睛常见的死锁形式:当线程1已经占据资源R1,并
- 本文实例讲述了散列表的原理与Java实现方法。分享给大家供大家参考,具体如下:概述符号表是一种用于存储键值对(key-value pair)
- 一、医院接口本文继续开发分布式医疗挂号系统,进入到医院信息、科室、排版接口的开发,内容比较枯燥。关于医院医院信息的上传接口实现,已经在上一篇
- 本文实例总结了Android开发之资源文件用法。分享给大家供大家参考,具体如下:这里记录在Android开发中经常用到的一些用法arrays
- Android package属性、package name和Application ID三者的联系及区别package属性:在Androi
- SpringBoot实战电商项目mall(30k+star)地址:https://github.com/macrozheng/mall摘要权
- 一,网络编程中两个主要的问题一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输。在TCP/IP协议中I
- 使用ExecutorService来停止线程服务之前的文章中我们提到了ExecutorService可以使用shutdown和shutdow
- webservice restful接口跟soap协议的接口实现大同小异,只是在提供服务的类/接口的注解上存在差异,具体看下面的代码,然后自
- service有两种类型:本地服务(Local Service):用于应用程序内部远程服务(Remote Sercie):用于android