华为OD机试 - 区间交集 - 深度优先搜索dfs算法(滥用)(Java 2023 B卷 200分)

在这里插入图片描述

目录

    • 专栏导读
    • 一、题目描述
    • 二、输入描述
    • 三、输出描述
      • 备注
      • 用例
        • 1、输入
        • 2、输出
        • 3、说明
    • 四、解题思路
      • 1、核心思路:
      • 2、具体步骤
    • 五、Java算法源码
      • 再重新读一遍题目,看看能否优化一下~
      • 解题步骤也简化了很多。
    • 六、效果展示
      • 1、输入
      • 2、输出
      • 3、说明

华为OD机试 2023B卷题库疯狂收录中,刷题点这里

专栏导读

本专栏收录于《华为OD机试(JAVA)真题(A卷+B卷)》。

刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试,发现新题目,随时更新,全天CSDN在线答疑。

一、题目描述

给定一组闭区间,其中部分区间存在交集。

任意两个给定区间的交集,称为公共区间(如:[1,2],[2,3]的公共区间为[2,2],[3,5],[3,6]的公共区间为[3,5])公共区间之间若存在交集,则需要合并(如:[1,3],[3,5]区间存在交集[3,3],需合并为[1,5])。按升序排列输出合并后的区间列表。

二、输入描述

组区间列表

区间数为 N: O<=N<=1000。

区间元素为 X:-10000<=X<=10000。

三、输出描述

升序排列的合并区间列表

备注

  1. 区间元素均为数字,不考虑字母、符号等异常输入。
  2. 单个区间认定为无公共区间。

用例

1、输入

4
0 3
1 3
3 5
3 6

2、输出

[1,5]

3、说明
  • 0 3和1 3的公共区间是1 3
  • 0 3和3 5的公共区间是3 3
  • 0 3和3 6的公共区间是3 3
  • 1 3和3 5的公共区间是3 3
  • 1 3和3 6的公共区间是3 3
  • 3 5和3 6的公共区间是3 5
  • 两两组合求出公共区间,去重,变为[1,3][3,3][3,5]
  • 若公共区间存在交集,合并为[1,5]

四、解题思路

第一反应是通过深度优先搜索dfs算法来解。

1、核心思路:

  1. 两两组合求出公共区间,左右分别相比,谁小取谁,删除重复的公共区间 [1,3][3,3][3,5]
  2. 有交集就合并,没交集就直接输出,左边谁小取谁,右边谁大取谁 [1,5]

2、具体步骤

  1. 第一行输入一个数字n,表示公共区间的数量;
  2. 接下来的n行,是具体的公共区间,并添加到集合list中;
  3. 两两组合求出公共区间,左右分别相比,谁小取谁,删除重复的公共区间;
    • 如果list就剩一个了,就不用比了;
    • 第一个数组 与 余下的数组进行两两比较;
    • 比较过的直接移除;
    • 遍历余下的数组;
      • 两个区间有交集;
      • 取交集,左取大,右取小;
      • 判断公共区间是否存在,如果不存在,加入到公共区间集合中;
    • 再取下一个第一个数组,再与余下的数组进行两两比较,循环往复;
  4. 有交集就合并,没交集就直接输出,左边谁小取谁,右边谁大取谁;
    • 如果list就剩一个了,就不用比了;
    • 第一个数组 与 余下的数组进行两两比较;
    • 此时不能直接删除,因为合并的才可以删除,不能合并的,直接输出即可;
    • 遍历余下的数组;
    • 当有交集时;
      • 左边谁小取谁,右边谁大取谁;
      • 删除有交集的区间;
      • 将合并后的区间加入到list,再进行比较合并;
      • 可以合并,重置mergeFlag为true,表示list中的数组还可以继续合并;
    • 如果当前比较的第一个数组,不能与余下的数组进行合并,将其删除;
      • 能与余下的数组进行合并的区间;
      • 可以合并,表示list中的数组还可以继续合并,重置合并表示为false;
    • 取第一个区间,与余下的区间进行合并,循环往复
  5. 按照左区间升序排序,如果相等,再按右区间升序排序;
  6. 将合并后的公共区间添加到builder中,输出即可。

五、Java算法源码

public class OdTest07 {
    // 公共区间集合
    static List<int[]> publicRangeList = new ArrayList<>();

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = Integer.valueOf(sc.nextLine());
        List<int[]> list = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            int[] arr = Arrays.stream(sc.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
            list.add(arr);
        }

        // 两两组合求出公共区间,左右分别相比,谁小取谁,删除重复的公共区间 [1,3][3,3][3,5]
        dfs(list);

        // 有交集就合并,没交集就直接输出,左边谁小取谁,右边谁大取谁 [1,5]
        mergeDfs(publicRangeList);

        publicRangeList.addAll(unMergeList);

        // 按照左区间升序排序,如果相等,再按右区间升序排序
        publicRangeList.sort((a, b) -> a[0] != b[0] ? a[0] - b[0] : a[1] - b[1]);

        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < publicRangeList.size(); i++) {
            builder.append(publicRangeList.get(i)[0]).append(" ").append(publicRangeList.get(i)[1]).append("\n");
        }
        System.out.println(builder.deleteCharAt(builder.length() - 1));
    }

    // 两两组合求出公共区间
    private static void dfs(List<int[]> list) {
        // 如果list就剩一个了,就不用比了
        if (list.size() == 1) {
            return;
        }

        // 第一个数组 与 余下的数组进行两两比较
        int[] firstArr = list.get(0);
        int left = firstArr[0];
        int right = firstArr[1];

        // 比较过的直接移除
        list.remove(0);
        // 余下的数组
        for (int i = 0; i < list.size(); i++) {
            // 余下的数组
            int[] comareArr = list.get(i);
            // 两个区间有交集
            if (right >= comareArr[0] && comareArr[1] >= left) {
                // 取交集,左取大,右取小
                int compareLeft = left <= comareArr[0] ? comareArr[0] : left;
                int compareRight = right <= comareArr[1] ? right : comareArr[1];
                int[] range = new int[]{compareLeft, compareRight};
                // 判断公共区间是否存在,如果不存在,加入到公共区间集合中
                if (!compareArr(range)) {
                    publicRangeList.add(range);
                }
            }
        }
        // 再取下一个第一个数组,再与余下的数组进行两两比较,循环往复
        dfs(list);
    }

    // 判断公共区间是否存在
    private static boolean compareArr(int[] arr) {
        for (int i = 0; i < publicRangeList.size(); i++) {
            int[] rangeArr = publicRangeList.get(i);
            if (arr[0] == rangeArr[0] && arr[1] == rangeArr[1]) {
                return true;
            }
        }
        return false;
    }

    // 是否可以合并
    static boolean mergeFlag = false;
    // 不能合并的数组区间
    static List<int[]> unMergeList = new ArrayList<>();

    // 有交集就合并,没交集就直接输出,左边谁小取谁,右边谁大取谁
    private static void mergeDfs(List<int[]> list) {
        // 如果list就剩一个了,就不用比了
        if (list.size() == 1) {
            return;
        }

        // 第一个数组 与 余下的数组进行两两比较
        // [3,6][5,6][5,7][6,6][6,7][6,8][9,10]
        int[] firstArr = list.get(0);
        int left = firstArr[0];
        int right = firstArr[1];
        // 此时不能直接删除,因为合并的才可以删除,不能合并的,直接输出即可
        // 余下的数组
        for (int i = 1; i < list.size(); i++) {
            int[] comareArr = list.get(i);
            // [9,10][3,6][5,7][6,8]
            // 当有交集时
            if (right >= comareArr[0] && comareArr[1] >= left) {
                // 左边谁小取谁,右边谁大取谁
                int compareLeft = left <= comareArr[0] ? left : comareArr[0];
                int compareRight = right <= comareArr[1] ? comareArr[1] : right;
                int[] range = new int[]{compareLeft, compareRight};
                // 删除有交集的区间
                list.remove(firstArr);
                list.remove(comareArr);
                // 将合并后的区间加入到list,再进行比较合并
                list.add(range);
                // 可以合并,表示list中的数组还可以继续合并
                mergeFlag = true;
                break;
            }
        }

        // 如果当前比较的第一个数组,不能与余下的数组进行合并,将其删除
        if (!mergeFlag) {
            list.remove(firstArr);
            // 能与余下的数组进行合并的区间
            unMergeList.add(firstArr);
        } else {// 可以合并,表示list中的数组还可以继续合并
            // 重置合并表示为false
            mergeFlag = false;
        }
        // 取第一个区间,与余下的区间进行合并,循环往复
        mergeDfs(list);
    }
}

感觉这道题,不至于这么复杂吧。

再重新读一遍题目,看看能否优化一下~

因为最近一直在刷dfs的算法题,所以第一反应是采用dfs来解,不过,普通的for循环就可以解决了,确实简单了很多,找准方向才最重要~

核心思想没什么变化。

解题步骤也简化了很多。

  1. 第一行输入一个数字n,表示公共区间的数量;
  2. 接下来的n行,是具体的公共区间,并添加到集合list中;
  3. 按照左区间升序排序,如果相等,再按右区间升序排序;
  4. 定义公共区间集合publicRangeList;
  5. 遍历list,每一个数组与后面的数组分别比较,取交集;
    • 两个区间有交集,左右分别相比,取交集,左取大,右取小;
  6. 按照左区间升序排序,如果相等,再按右区间升序排序;
  7. 定义合并后的区间数组builder;
  8. 获取第一个有效的合并区间mergeArr;
  9. 遍历公共区间集合publicRangeList;
    • 有交集,取右区间的最大值;
    • 没有交集,拼接到合并的区间数组builder中;
    • 重置有效的合并区间为下一个区间;
  10. 输出合并后的区间数组即可。
public class OdTest07 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = Integer.valueOf(sc.nextLine());
        List<int[]> list = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            int[] arr = Arrays.stream(sc.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
            list.add(arr);
        }

        // 按照左区间升序排序,如果相等,再按右区间升序排序
        list.sort((a, b) -> a[0] != b[0] ? a[0] - b[0] : a[1] - b[1]);

        // 公共区间集合
        List<int[]> publicRangeList = new ArrayList<>();

        // 遍历list,每一个数组与后面的数组分别比较,取交集
        for (int i = 0; i < list.size(); i++) {
            int[] arr = list.get(i);
            for (int j = i + 1; j < list.size(); j++) {
                int[] nextArr = list.get(j);
                // 两个区间有交集
                if (arr[1] >= nextArr[0]) {
                    // 左右分别相比,取交集,左取大,右取小
                    publicRangeList.add(new int[]{Math.max(arr[0], nextArr[0]), Math.min(arr[1], nextArr[1])});
                }
            }
        }

        // [3,6][5,6][6,6][5,7][6,8][6,7][9,10]
        if (publicRangeList.size() == 0) {
            System.out.println("None");
            return;
        }

        // [3,6][5,6][5,7][6,6][6,7][6,8][9,10]
        publicRangeList.sort((a, b) -> a[0] != b[0] ? a[0] - b[0] : a[1] - b[1]);

        // 合并后的区间数组
        StringBuilder builder = new StringBuilder();
        // 有效的合并区间
        int[] mergeArr = publicRangeList.get(0);
        for (int i = 1; i < publicRangeList.size(); i++) {
            int[] nextArr = publicRangeList.get(i);
            // 有交集,取右区间的最大值
            if (mergeArr[1] >= nextArr[0]) {
                mergeArr[1] = Math.max(mergeArr[1], nextArr[1]);
            } else {// 没有交集,拼接到合并的区间数组builder中
                builder.append(mergeArr[0]).append(" ").append(mergeArr[1]).append("\n");
                // 重置有效的合并区间为下一个区间
                mergeArr = nextArr;
            }
        }
        builder.append(mergeArr[0]).append(" ").append(mergeArr[1]).append("\n");
        // 输出合并后的区间数组
        System.out.println(builder.deleteCharAt(builder.length() - 1));
    }
}

六、效果展示

1、输入

5
9 10
5 7
6 11
3 8
3 6

2、输出

3 8
9 10

3、说明

  • 3 6和3 8的公共区间是3 6
  • 3 6和5 7的公共区间是5 6
  • 3 6和6 11的公共区间是6 6
  • 3 6和9 10的公共区间是无
  • 3 8和5 7的公共区间是5 7
  • 3 8和6 11的公共区间是6 8
  • 3 8和9 10的公共区间是无
  • 5 7和6 11的公共区间是6 7
  • 5 7和9 10的公共区间是无
  • 6 11和9 10的公共区间是9 10
  • 两两组合求出公共区间:[3,6][5,6][6,6][5,7][6,8][6,7][9,10]
  • 有交集就合并,没交集就直接输出:[3,8][9,10]

在这里插入图片描述


🏆下一篇:华为OD机试 - 最长的顺子 - 感谢@禁止你发言提供的更简便算法(Java 2023 B卷 200分)

🏆本文收录于,华为OD机试(JAVA)真题(A卷+B卷)

刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试,发现新题目,随时更新,全天CSDN在线答疑。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

用最通俗的语言讲解 TCP “三次握手,四次挥手”

目录 一. 前言 二. TCP 报文的头部结构 三. 三次握手 3.1. 三次握手过程 3.2. 为什么要三次握手 四. 四次挥手 4.1. 四次挥手过程 4.2. 为什么要四次挥手 五. 大白话说 5.1. 大白话说三次握手 5.2. 大白话说四次挥手 六. 总结 一. 前言 TCP 是一种面向连接的、可靠…

【SpringBoot快速入门】(3)SpringBoot整合junit和MyBatis 详细代码示例与讲解

目录 1.SpringBoot整合junit1.1 环境准备1.2 编写测试类 2.SpringBoot整合mybatis2.1 回顾Spring整合Mybatis2.2 SpringBoot整合mybatis2.2.1 创建模块2.2.2 定义实体类2.2.3 定义dao接口2.2.4 定义测试类2.2.5 编写配置2.2.6 测试2.2.7 使用Druid数据源 之前我们已经学习的Spr…

I.MX6ULL_Linux_驱动篇(47)linux RTC驱动

RTC 也就是实时时钟&#xff0c;用于记录当前系统时间&#xff0c;对于 Linux 系统而言时间是非常重要的&#xff0c;就和我们使用 Windows 电脑或手机查看时间一样&#xff0c;我们在使用 Linux 设备的时候也需要查看时间。本章我们就来学习一下如何编写 Linux 下的 RTC 驱动程…

spring boot回顾02

配置文件 SpringBoot使用一个全局的配置文件 &#xff0c; 配置文件名称是固定的 application.properties 语法结构 &#xff1a;keyvalue application.yml 语法结构 &#xff1a;key&#xff1a;空格 value 配置文件的作用 &#xff1a;修改SpringBoot自动配置的默认值&am…

低功耗 电源管理 SCMI接口

SCMI overview&#xff1a; SCMI 协议&#xff1a;

本地websocket服务端结合cpolar内网穿透实现公网访问

文章目录 1. Java 服务端demo环境2. 在pom文件引入第三包封装的netty框架maven坐标3. 创建服务端,以接口模式调用,方便外部调用4. 启动服务,出现以下信息表示启动成功,暴露端口默认99995. 创建隧道映射内网端口6. 查看状态->在线隧道,复制所创建隧道的公网地址加端口号7. 以…

VMware克隆虚拟机

要求&#xff1a;利用模板虚拟机hadoop100&#xff0c;克隆出hadoop101虚拟机。 1、鼠标右键点击已存在的模板虚拟机hadoop100 --> 管理 --> 克隆 2、选择克隆自虚拟机中的当前状态 3、创建完整克隆 4、修改虚拟机名称、位置 5、等待克隆完成后&#xff0c;则成功克隆出…

Debian在升级过程中报错

当我们在升级的过程中出现如下报错信息 报错信息如下所示&#xff1a; The following signatures couldnt be verified because the public key is not available: NO_PUBKEY ED444FF07D8D0BF6 W: GPG error: http://mirrors.jevincanders.net/kali kali-rolling InRelease: …

CentOS安装jdk

1、查看可安装版本 yum -y list java* 2、安装jdk1.8版本 yum -y install java-1.8.0-openjdk 3、查看版本 java -version 4、安装目录为&#xff1a; /usr/lib/jvm 5、卸载 yum -y remove java-1.8.0-openjdk

干洗店预约上门取货小程序与互联网洗鞋店小程序开发制作功能方案

干洗店预约上门取货小程序与互联网洗鞋店小程序开发制作功能方案 一、洗衣洗鞋店小程序功能 1. 预约订单&#xff1a;忙碌时&#xff0c;您可以使用预约功能轻松获取洗衣服务。 2. 在线下单&#xff1a;用户可直接通过小程序在线下单&#xff0c;享受专人上门取货与配送服务。…

Windows下Navicat15.0连接Oracle11g报ORA-28547解决

目录 背景 一、相关环境 1、操作系统 2、Navicat版本 3、ORACLE连接 4、默认连接 二、问题分析 1、默认dll配置 三、修改配置 1、下载匹配的client 2、替换相应目录 总结 背景 最近在项目中需要使用Oracle数据库&#xff0c;当前很多应用系统的数据都存储在MySQL或者Pos…

JRT整合下载文件api

以前最古老的是用的FTP存文件&#xff0c;所以原始的文件操作是直接操作FTP&#xff0c;后面随着使用发现FTP对端口要求太多了&#xff0c;容易出问题&#xff0c;新的安保方面也提安全方面问题&#xff0c;就转http文件服务了。为了同时兼容两种文件服务&#xff0c;此时就抽取…

用户管理第2节课-idea 2023.2 后端一删除表,从零开始---【本人】

一、清空model文件夹下&#xff0c;所有文件 1.1.1效果如下&#xff1a; 1.1代码内容 package com.daisy.usercenter.model;import lombok.Data;Data public class User {private Long id;private String name;private Integer age;private String email; }二、清空mapper文件…

文档理解的新时代:LayOutLM模型的全方位解读

一、引言 在现代文档处理和信息提取领域&#xff0c;机器学习模型的作用日益凸显。特别是在自然语言处理&#xff08;NLP&#xff09;技术快速发展的背景下&#xff0c;如何让机器更加精准地理解和处理复杂文档成为了一个挑战。文档不仅包含文本信息&#xff0c;还包括布局、图…

使用 Docker 部署企业培训系统 PlayEdu

1&#xff09;PlayEdu 介绍 官网&#xff1a;https://www.playedu.xyz/ GitHub&#xff1a;https://github.com/PlayEdu/PlayEdu PlayEdu 是一款适用于搭建内部培训平台的开源系统&#xff0c;旨在为企业/机构打造自己品牌的内部培训平台。PlayEdu 基于 Java MySQL 开发&…

ctfshow sql 195-200

195 堆叠注入 十六进制 if(preg_match(/ |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\#|\x23|\|\"|select|union|or|and|\x26|\x7c|file|into/i, $username)){$ret[msg]用户名非法;die(json_encode($ret));}可以看到没被过滤&#xff0c;select 空格 被过滤了&#xff0c;可…

KylinV10 安装 MySQL 教程(可防踩雷)

KylinV10 安装 MySQL 教程&#xff08;可防踩雷&#xff09; 1、直接用 apt 快捷安装 MySQL $ sudo apt-get update #更新软件源 $ sudo apt-get install mysql-server #安装mysql然后你会发现&#xff0c;KylinV10 安装畅通无阻&#xff0c;并没有设置密码的场景&#xff0c…

SQLiteStudio安装指南

本博文源于笔者想要打开sqlite3的db文件&#xff0c;于是下载了SQLiteStudio&#xff0c;下载了它&#xff0c;sqlite3的文件随便查看&#xff0c;这里从零开始安装 文章目录 1、搜索官网网址2、开始下载3、开始安装4、开始使用5、总结 1、搜索官网网址 官网地址&#xff1a;…

【Vue中给输入框加入js验证_blur失去焦点进行校验】

【Vue中给输入框加入js验证_blur失去焦点进行校验】 通俗一点就是给输入框加个光标离开当前文本输入框时&#xff0c;然后对当前文本框内容进行校验判断 具体如下&#xff1a; 1.先给文本框加属性 blur“validatePhoneNumber” <el-input v-model“entity.telephone” blur…

挑选办公网盘指南:2023年值得推荐的办公网盘品牌

企业团队在选择办公网盘时&#xff0c;可以通过什么维度进行工具好坏的评判&#xff1f;如何判断网盘的优劣&#xff1f;2023年国内又有哪些值得推荐的网盘品牌呢&#xff1f; 首先是如何选择网盘&#xff1f; 在网盘选择时&#xff0c;我们可以从以下四个方面进行评测&#x…