Java C++题解leetcode886可能的二分法并查集染色法

 更新时间:2022年10月17日 10:23:37   作者:AnjaVon  
这篇文章主要为大家介绍了Java C++题解leetcode886可能的二分法并查集染色法实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

题目要求

思路一:反向点+并查集

  • 根据题意不喜欢就不在一个组可以想到使用并查集,本题是两个集合所以对每一个节点引入一个反向点,使两者分属于不同集合,借此记录前续节点维持的不喜欢关系;
  • 在将每个节点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)

总结

算法题就回避一下Rust……待我学成归来……

填了拖了好久的并查集的坑还捎带复习了一波链式前向星存图;

感觉链式前向星忘得差不多了……

以上就是Java C++题解leetcode886可能的二分法并查集染色法的详细内容,更多关于Java C++ 可能的二分法的资料请关注脚本之家其它相关文章!

相关文章

  • Java自定义一个变长数组的思路与代码

    Java自定义一个变长数组的思路与代码

    有时我们希望将把数据保存在单个连续的数组中,以便快速、便捷地访问数据,但这需要调整数组大小或者对其扩展,下面这篇文章主要给大家介绍了关于Java自定义一个变长数组的思路与代码,需要的朋友可以参考下
    2022-12-12
  • JAVA编程不能不知道的反射用法总结

    JAVA编程不能不知道的反射用法总结

    这篇文章主要介绍了Java反射技术原理与用法,结合实例形式分析了Java反射技术的基本概念、功能、原理、用法及操作注意事项,需要的朋友可以参考下
    2021-07-07
  • Java基于中介者模式实现多人聊天室功能示例

    Java基于中介者模式实现多人聊天室功能示例

    这篇文章主要介绍了Java基于中介者模式实现多人聊天室功能,详细分析了中介者模式的概念、原理以及使用中介模式实现多人聊天的步骤、操作技巧与注意事项,需要的朋友可以参考下
    2018-05-05
  • java获取本月日历表的方法

    java获取本月日历表的方法

    这篇文章主要为大家详细介绍了java获取本月日历表的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • SpringMvc框架的简介与执行流程详解

    SpringMvc框架的简介与执行流程详解

    MVC是一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个组件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑,MVC分层有助于管理和架构复杂的应用程序
    2021-06-06
  • 浅谈String类型如何转换为time类型存进数据库

    浅谈String类型如何转换为time类型存进数据库

    这篇文章主要介绍了String类型如何转换为time类型存进数据库,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • Java几个实例带你进阶升华下篇

    Java几个实例带你进阶升华下篇

    与其明天开始,不如现在行动,本文为你带来几个Java书写的实际案例,对巩固编程的基础能力很有帮助,快来一起往下看看吧
    2022-03-03
  • Java爬虫(Jsoup与WebDriver)的使用

    Java爬虫(Jsoup与WebDriver)的使用

    这篇文章主要介绍了Java爬虫(Jsoup与WebDriver)的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • 浅谈Java double 相乘的结果偏差小问题

    浅谈Java double 相乘的结果偏差小问题

    下面小编就为大家带来一篇浅谈Java double 相乘的结果偏差小问题。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01
  • Java发送form-data请求的实例代码

    Java发送form-data请求的实例代码

    在Java中发送form-data请求,可以使用Apache HttpClient或OkHttp这样的HTTP客户端库来发送请求,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2023-10-10

最新评论