题目要求

思路一:反向点 并查集

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

Java C++题解leetcode886可能的二分法并查集染色法的更多相关文章

  1. Swift语言和其他计算机语言的比较

    Swift集成了传统面向对象编程语言的特性,同时又具备函数式编程的一些特征。在2014年WWDC之前,用来开发iOS应用的语言被称为Objective-C,它是标准C语言的扩展。使用Objective-C可以完成C语言所能完成的任何工作。这里不得不提到C++语言,事实上C++和Objective-C语言几乎是同时出现的。和Objective-C语言的简洁不同,C++语言几乎包含了所有可能的特性。

  2. Swift Name Mangling - Swift语言的名字重整技术

    在比如C这样的语言中,任何给定的名字(符号)只能对应唯一的一个函数或数据,不需要名字重整。因此,c++编译器使用一组严格的编码规则“mangles”(重整)了符号。想获取更多的关于经典C++编译器重整名字的内容,请参考ItaniumC++ABIdocumentation.总结:Object-C类似于C语言,Swift类似于C++,有函数重载,有虚函数表,需要命名重整。

  3. 你是如何评价Swift的,谈谈你的感受!

    假如之前已经掌握了Objective-C,切换到Swift也不难。Swift还没有很好地解决好跟C和C++混编的问题。随着时间推移,Swift在整个iOS/Mac工程中占的代码比例会越来越多,而Objective-C作为粘合层还是会存在。只是等你真正使用Swift编写一两个项目,就回不了头。Swift有些简便快速的写法,在Objective-C中是没有办法做到的。并且Swift的一些语言特性避免了很多Objective-C的坑。使用Swift编写的任何功能,使用Objective-C也可以做到,但是会麻烦

  4. 2017 年热门编程语言排行榜,你的语言上榜没?

    2016年11月的排名结果显示,Java依然是最受大家欢迎的语言,C和C++排名紧随其后。GitHub在2016年9月年度会议之前,Github在此分享了其统计报告。随后它在平台上公布了热门语言排行表。该公司支持30多种编程语言,用户可随心选择。按照使用量排名,Java排在第一位,Javascript,PHP和C以一万多的差距尾随其后。

  5. 在Android上解码Java或C/C++中的Airplay数据包

    提前致谢马特解决方法虽然Java编译为在虚拟机中运行的字节码,但它可能不一定比本机编译的可执行文件更慢(或更快).这一切都取决于程序!在这种情况下,Java可能会变慢,原因有很多:>解码实现可能只是编码/优化不佳?(我必须在这里注意,我不是Java的专家!)但是,我仍然不会调用Java本质上比C或C慢.我相信你可以在互联网上找到many-abenchmarks和测试,比较一种语言和另一种语言,有些人声称在一定程度上(出于骄傲和自我?

  6. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  7. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  8. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  9. Java实现世界上最快的排序算法Timsort的示例代码

    Timsort 是一个混合、稳定的排序算法,简单来说就是归并排序和二分插入排序算法的混合体,号称世界上最好的排序算法。本文将详解Timsort算法是定义与实现,需要的可以参考一下

  10. Java日期工具类的封装详解

    在日常的开发中,我们难免会对日期格式化,对日期进行计算,对日期进行校验,为了避免重复写这些琐碎的逻辑,我这里封装了一个日期工具类,方便以后使用,直接复制代码到项目中即可使用,需要的可以参考一下

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部