代码随想录算法训练营第五十八天|108.冗余连接、109.冗余连接II

news2024/9/21 0:33:59

108.冗余连接

在这里插入图片描述
在这里插入图片描述

题目链接:108.冗余连接
文档讲解:代码随想录
状态:还行

思路:
并查集可以解决什么问题:两个节点是否在一个集合,也可以将两个节点添加到一个集合中。

题解:


public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt(); // 读取图中的边数
        UnionFind uf = new UnionFind(n + 1); // 初始化并查集,节点数为n+1
        for (int i = 0; i < n; i++) {
            int s = scanner.nextInt(); // 读取一条边的起点
            int t = scanner.nextInt(); // 读取一条边的终点
            if (uf.isSame(s, t)) { // 判断起点和终点是否属于同一个集合
                System.out.println(s + " " + t); // 如果是同一个集合,输出这条冗余边
                return; // 结束程序
            }
            uf.join(s, t); // 将起点和终点加入同一个集合
        }
    }

    static class UnionFind {
        private int n; // 节点数
        private int[] father; // 父节点数组

        public UnionFind(int n) {
            this.n = n; // 初始化节点数
            father = new int[n]; // 初始化父节点数组
            init(); // 初始化父节点数组
        }

        private void init() {
            for (int i = 0; i < n; i++) {
                father[i] = i; // 将每个节点的父节点初始化为自身
            }
        }

        private int find(int u) {
            // 查找节点u的根节点,并进行路径压缩
            return father[u] == u ? u : (father[u] = find(father[u]));
        }

        public void join(int u, int v) {
            // 将节点u和节点v的集合合并
            u = find(u); // 找到节点u的根节点
            v = find(v); // 找到节点v的根节点
            if (u != v) {
                father[v] = u; // 将节点v的根节点设置为u
            }
        }

        public boolean isSame(int u, int v) {
            // 判断节点u和节点v是否属于同一个集合
            return find(u) == find(v);
        }
    }
}

109.冗余连接II

题目链接:109.冗余连接II
文档讲解:代码随想录
状态:不会

思路:

可能情况
1.存在有环边
在这里插入图片描述
2.存在入度为2的顶点
在这里插入图片描述
3.同时存在有环边和入度为2的顶点
在这里插入图片描述

解题思路可以分为三种情况:

节点的入度为2:如果一个节点有两条入边,删除其中一条边会使得图变成树。
构成环的边:如果没有节点的入度为2,那么一定有一个环。删除环中的任意一条边会使得图变成树。

public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt(); // 读取图中的节点数
        int[][] edges = new int[n][2]; // 存储每条边的起点和终点
        int[] inDegree = new int[n + 1]; // 记录每个节点的入度
        UnionFind uf = new UnionFind(n + 1); // 初始化并查集,节点数为n+1
        for (int i = 0; i < n; i++) {
            int s = scanner.nextInt(); // 读取一条边的起点
            int t = scanner.nextInt(); // 读取一条边的终点
            inDegree[t]++; // 终点节点的入度加1
            edges[i][0] = s;
            edges[i][1] = t;
        }
        List<Integer> vec = new ArrayList<>(); // 记录入度为2的边(如果有的话就两条边)
        // 找入度为2的节点所对应的边,注意要倒序,因为优先删除最后出现的一条边
        for (int i = n - 1; i >= 0; i--) {
            if (inDegree[edges[i][1]] == 2) {
                vec.add(i);
            }
        }
        if (!vec.isEmpty()) {
            // 放在vec里的边已经按照倒叙放的,所以这里就优先删vec.get(0)这条边
            if (uf.isTreeAfterRemoveEdge(edges, vec.get(0), n)) {
                System.out.println(edges[vec.get(0)][0] + " " + edges[vec.get(0)][1]);
            } else {
                System.out.println(edges[vec.get(1)][0] + " " + edges[vec.get(1)][1]);
            }
            return;
        }
        // 处理情况三
        // 明确没有入度为2的情况,那么一定有有向环,找到构成环的边返回就可以了
        uf.getRemoveEdge(edges, n);
    }

    // 并查集类
    static class UnionFind {
        private int n; // 节点数
        private int[] father; // 父节点数组

        public UnionFind(int n) {
            this.n = n; // 初始化节点数
            father = new int[n]; // 初始化父节点数组
            init(); // 初始化父节点数组
        }

        private void init() {
            // 将每个节点的父节点初始化为自身
            for (int i = 0; i < n; i++) {
                father[i] = i;
            }
        }

        // 查找节点u的根节点,并进行路径压缩
        private int find(int u) {
            if (u != father[u]) {
                father[u] = find(father[u]);
            }
            return father[u];
        }

        // 将节点u和节点v的集合合并
        public void join(int u, int v) {
            u = find(u); // 找到节点u的根节点
            v = find(v); // 找到节点v的根节点
            if (u != v) {
                father[v] = u; // 将节点v的根节点设置为u
            }
        }

        // 判断节点u和节点v是否属于同一个集合
        public boolean isSame(int u, int v) {
            return find(u) == find(v);
        }

        // 在有向图里找到删除的那条边,使其变成树
        void getRemoveEdge(int[][] edges, int n) {
            init(); // 初始化并查集
            for (int i = 0; i < n; i++) { // 遍历所有的边
                if (isSame(edges[i][0], edges[i][1])) { // 构成有向环了,就是要删除的边
                    System.out.println(edges[i][0] + " " + edges[i][1]);
                    return;
                } else {
                    join(edges[i][0], edges[i][1]);
                }
            }
        }

        // 删一条边之后判断是不是树
        boolean isTreeAfterRemoveEdge(int[][] edges, int deleteEdge, int n) {
            init(); // 初始化并查集
            for (int i = 0; i < n; i++) {
                if (i == deleteEdge) continue; // 跳过要删除的边
                if (isSame(edges[i][0], edges[i][1])) { // 构成有向环了,一定不是树
                    return false;
                }
                join(edges[i][0], edges[i][1]);
            }
            return true;
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1935910.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

套用BI方案做数据可视化是种什么体验?

在数字化转型的浪潮中&#xff0c;数据可视化作为连接数据与决策的桥梁&#xff0c;其重要性日益凸显。近期&#xff0c;我有幸体验了奥威BI方案进行数据可视化的全过程&#xff0c;这不仅是一次技术上的探索&#xff0c;更是一次对高效、智能数据分析的深刻感受。 初识奥威&a…

.net dataexcel 脚本公式 函数源码

示例如: ScriptExec(""sum(1, 2, 3, 4)"") 结果等于10 using Feng.Excel.Builder; using Feng.Excel.Collections; using Feng.Excel.Interfaces; using Feng.Script.CBEexpress; using Feng.Script.Method; using System; using System.Collections.Gen…

场景分析法挖掘需求的常见4大步骤

场景分析方法&#xff0c;有助于精确定位需求&#xff0c;优化产品设计&#xff0c;促进团队协同&#xff0c;减少项目风险&#xff0c;提升用户满意度与市场竞争力。若场景分析不足&#xff0c;产品可能偏离用户需求&#xff0c;导致功能冗余或缺失&#xff0c;用户体验差&…

java中传引用问题

在 Java 中&#xff0c;所有对象都是通过引用传递的&#xff0c;而基本数据类型是通过值传递的。 引用传递&#xff1a; 当一个对象作为参数传递给方法时&#xff0c;传递的是对象的引用。对这个对象引用进行的修改会影响到原始对象。例如&#xff1a; public class Test {p…

Designing Data-Intensive Applications数据密集型应用系统设计-读书笔记

目录 第一部分可靠性、可扩展性、可维护性硬件故障描述负载 吞吐与延迟可维护性 第二章 数据模型与查询语言第三章索引哈希索引B-tree事务 第三章 编码第二部分、分布式数据系统第五章 数据复制单主从复制节点失效日志实现复制滞后问题 多主节点复制 第六章、数据分区3 第一部分…

10个常见的电缆载流表,值得收藏!

众所周知,电线电缆的载流是所有电工、电气人员都必须具备的基本储备,但是如果要将那么多的“数字”都记得清清楚楚,还是有一点困难的!今天咱们就做了一个电力电缆载流量对照表,速度收藏!下次参考不迷路! 1、0.6/1KV聚氯乙烯绝缘电力电缆载流量 以上电缆载流量计算条件:…

世界启动Ⅳ--利用AI和费曼技巧学习一切

前言 有无数的学习技巧可以帮助你消化复杂的概念&#xff0c;并有信心记住它们。如果你像我一样是一个不断学习的学生&#xff0c;你就会明白有效学习方法的重要性。其中最简单的一种就是费曼技巧。 在本文中&#xff0c;我将解释如何有效地应用费曼学习方法&#xff0c;以及…

应用最优化方法及MATLAB实现——第5章代码实现

一、概述 继上一章代码后&#xff0c;这篇主要是针对于第5章代码的实现。部分代码有更改&#xff0c;会在下面说明&#xff0c;程序运行结果跟书中不完全一样&#xff0c;因为部分参数&#xff0c;书中并没有给出其在运行时设置的值&#xff0c;所以我根据我自己的调试进行了设…

迁移学习在乳腺浸润性导管癌病理图像分类中的应用

1. 引言 乳腺癌主要有两种类型:原位癌:原位癌是非常早期的癌症&#xff0c;开始在乳管中扩散&#xff0c;但没有扩散到乳房组织的其他部分。这也称为导管原位癌(DCIS)。浸润性乳腺癌:浸润性乳腺癌已经扩散(侵入)到周围的乳腺组织。侵袭性癌症比原位癌更难治愈。将乳汁输送到乳…

C++中的new和模版

前言 随着C的学习&#xff0c;讲了C的发展过程、流插入、流提取、函数缺省值、类与构造等等。接下来学习C很方便的 玩意&#xff0c;函数模版。函数模版就像是模具一样&#xff0c;C会自动用模版编译出合适的函数供程序员使用。以前不同类型相同操作的函数都能通过函数模版&…

【iOS】——内存对齐

内存对齐是什么 内存对齐指的是数据在内存中的布局方式&#xff0c;它确保每个数据类型的起始地址能够满足该类型对齐的要求。这是因为现代处理器在访问内存时&#xff0c;如果数据的起始地址能够对齐到一定的边界&#xff0c;那么访问速度会更快。这种对齐通常是基于数据类型…

客户中心应急管理的作用和特征

近些年作为事故、灾难等风险的预防主体和第一响应者&#xff0c;客户中心的应急管理取得了较大进展&#xff0c;但总体上仍存在很多薄弱环节&#xff0c;如安全事故频发&#xff0c;自然灾害、公共卫生、社会安全事件等给运营机构带来了多方面的不利影响。从信息角度看&#xf…

20240720 每日AI必读资讯

OpenAI 推出GPT-4o mini取代 GPT 3.5&#xff01; - 性能超越 GPT 4&#xff0c;而且更快更便宜 - 该模型在MMLU上得分为82%&#xff0c;在LMSYS排行榜上的聊天偏好测试中表现优于GPT-4。 - GPT-4o mini的定价为每百万输入标记15美分和每百万输出标记60美分&#xff0c;比之…

【golang-ent】go-zero框架 整合 ent orm框架 | 解决left join未关联报错的问题

一、场景 1、子表&#xff1a;cp_member_point_history cp_member_point_history表中字段&#xff1a;cp_point_reward_id 是cp_point_reward的主键id 当本表中的cp_point_reward_id字段为0&#xff08;即&#xff1a;没有可关联主表的&#xff09; CREATE TABLE cp_member_poi…

项目开发之文件上传 (秒传、断点续传、分片上传)(看这一篇就懂了)

目录&#xff1a; 前言秒传什么是秒传核心逻辑代码实现 小文件上传什么是小文件上传核心逻辑代码实现 分片上传什么是分片上传核心逻辑代码实现 断点续传什么是断点续传核心代码实现 前言 文件上传在项目开发中再常见不过了&#xff0c;大多项目都会涉及到图片、音频、视频、文…

npm安装依赖包报错,npm ERR! code ENOTFOUND

一、报错现象&#xff1a; npm WARN registry Unexpected warning for https://registry.npmjs.org/: Miscellaneous Warning ETIMEDOUT: request to https://registry.npmjs.org/vue failed, reason: connect ETIMEDOUT 104.16.23.35:443 npm WARN registry Using stale data…

Python | Leetcode Python题解之第235题二叉搜索树的最近公共祖先

题目&#xff1a; 题解&#xff1a; class Solution:def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:ancestor rootwhile True:if p.val < ancestor.val and q.val < ancestor.val:ancestor ancestor.leftelif p.val >…

【力扣】最小栈

&#x1f525;博客主页&#xff1a; 我要成为C领域大神&#x1f3a5;系列专栏&#xff1a;【C核心编程】 【计算机网络】 【Linux编程】 【操作系统】 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 设计一个支持 push…

object-C 解答算法:合并两个有序数组(leetCode-88)

合并两个有序数组(leetCode-88) 题目如下图:(也可以到leetCode上看完整题目,题号88) 首先搞懂,什么叫“非递减顺序” 非递减顺序,是指一个序列中的元素从前往后&#xff08;或从左到右&#xff09;保持不减少或相等。 这意味着序列中的元素可以保持相同的值&#xff0c;但不会…

c++ pc输入法例子

1、微软开源demo Windows-classic-samples/Samples/IME at master jiangdon2007/Windows-classic-samples (github.com) 2、打开SampleIME.sln 编译【32位或者64位】 3、将SampleIME.dll 和SampleIMESimplifiedQuanPin.txt 放在同一个目录 4、注册 regsvr32 SampleIME.dl…