华为OD机试 - 区间交叠问题 - 贪心算法(Python/JS/C/C++ 2024 E卷 200分)

news2024/11/24 0:17:37

在这里插入图片描述

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

专栏导读

本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。

一、题目描述

给定 坐标轴上的一组线段,线段的起点和终点均为整数并且长度不小于1,请你从中找到最少数量的线段,这些线段可以覆盖住所有线段。

二、输入描述

第一行输入为所有线段的数量,不超过10000,后面每行表示一条线段,格式为“x,y”,x和y分别表示起点和终点,取值范围是[-105, 105]。

三、输出描述

最少线段数量,为正整数。

四、测试用例

测试用例1:

1、输入

3
1,4
2,5
3,6

2、输出

2

3、说明

选择线段 [1,4] 和 [3,6],它们的并集覆盖了所有原始线段的区域 [1,6]。

测试用例2:

1、输入

4
1,2
2,3
3,4
4,5

2、输出

4

3、说明

需要选择所有线段 [1,2], [2,3], [3,4], [4,5] 来覆盖整个区间 [1,5]。

五、解题思路

题目要求从给定的一组线段中选择最少数量的线段,使得所有给定线段所覆盖的区域(即所有线段的并集)被选出的线段完全覆盖。换句话说,选出的线段的并集应包含所有原始线段的并集。

这是一个典型的区间覆盖问题,可以通过贪心算法高效地解决。

1、具体步骤如下

  1. 排序:
    • 将所有线段按照起点升序排序。如果起点相同,则按照终点降序排序。
  2. 贪心选择:
    • 初始化当前覆盖的右端点 currentEnd 为整个覆盖区间的起点(最小起点)。
    • 遍历排序后的线段,对于每一步,选择能够覆盖当前未覆盖部分且延伸最远的线段。
    • 每选择一条线段,就将 currentEnd 更新为该线段的终点,并增加选择计数。
  3. 终止条件:
    • 当 currentEnd 达到或超过所有线段的最大终点时,算法结束。

2、时间复杂度

排序的时间复杂度为 O(n log n),选择过程的时间复杂度为 O(n),总体时间复杂度为 O(n log n),适用于线段数量较大的情况(本题中不超过10000条)。

这种方法确保每次选择的线段都能尽可能延伸覆盖范围,从而最小化所需的线段数量。

六、Python算法源码

import sys

def main():
    import sys
    import sys
    # 读取所有输入
    input = sys.stdin.read().splitlines()
    if not input:
        print(0)
        return
    n = int(input[0])  # 读取线段数量
    segments = []
    for i in range(1, n+1):
        parts = input[i].split(',')
        start = int(parts[0])
        end = int(parts[1])
        if start > end:
            start, end = end, start  # 确保起点小于等于终点
        segments.append((start, end))
    
    # 按起点升序排序,如果起点相同,按终点降序排序
    segments.sort(key=lambda x: (x[0], -x[1]))
    
    count = 0  # 最少线段数量
    current_end = -float('inf')  # 当前覆盖的右端点
    max_end = -float('inf')  # 当前能覆盖到的最大右端点
    i = 0  # 当前线段索引
    n = len(segments)
    
    while i < n:
        # 如果当前线段的起点大于当前覆盖的右端点
        if segments[i][0] > current_end:
            # 找到所有起点 <= segments[i][0] 的线段中终点最大的
            max_end = segments[i][1]
            j = i + 1
            while j < n and segments[j][0] <= segments[i][0]:
                if segments[j][1] > max_end:
                    max_end = segments[j][1]
                j += 1
            count +=1
            current_end = max_end
            i = j
        else:
            # 找到所有起点 <= current_end 的线段中终点最大的
            max_end = current_end
            while i < n and segments[i][0] <= current_end:
                if segments[i][1] > max_end:
                    max_end = segments[i][1]
                i +=1
            if max_end > current_end:
                count +=1
                current_end = max_end
            else:
                i +=1
    
    print(count)

if __name__ == "__main__":
    main()

七、JavaScript算法源码

process.stdin.resume();
process.stdin.setEncoding('utf8');

let input = '';
process.stdin.on('data', function(chunk) {
    input += chunk;
});

process.stdin.on('end', function() {
    const lines = input.trim().split('\n');
    const n = parseInt(lines[0]); // 读取线段数量
    let segments = [];
    for (let i = 1; i <= n; i++) {
        let parts = lines[i].split(',');
        let start = parseInt(parts[0]);
        let end = parseInt(parts[1]);
        if (start > end) { // 确保起点小于等于终点
            [start, end] = [end, start];
        }
        segments.push([start, end]);
    }
    
    // 按起点升序排序,如果起点相同,按终点降序排序
    segments.sort((a, b) => {
        if (a[0] !== b[0]) {
            return a[0] - b[0];
        } else {
            return b[1] - a[1];
        }
    });
    
    let count = 0; // 最少线段数量
    let current_end = -Infinity; // 当前覆盖的右端点
    let i = 0;
    while (i < n) {
        if (segments[i][0] > current_end) {
            // 找到所有起点 <= segments[i][0] 的线段中终点最大的
            let max_end = segments[i][1];
            let j = i + 1;
            while (j < n && segments[j][0] <= segments[i][0]) {
                if (segments[j][1] > max_end) {
                    max_end = segments[j][1];
                }
                j++;
            }
            count++;
            current_end = max_end;
            i = j;
        } else {
            // 找到所有起点 <= current_end 的线段中终点最大的
            let max_end = current_end;
            while (i < n && segments[i][0] <= current_end) {
                if (segments[i][1] > max_end) {
                    max_end = segments[i][1];
                }
                i++;
            }
            if (max_end > current_end) {
                count++;
                current_end = max_end;
            } else {
                i++;
            }
        }
    }
    
    console.log(count);
});

八、C算法源码

#include <stdio.h>
#include <stdlib.h>

// 定义线段结构体
typedef struct {
    int start;
    int end;
} Segment;

// 比较函数,用于qsort排序
int compare(const void* a, const void* b) {
    Segment* segA = (Segment*)a;
    Segment* segB = (Segment*)b;
    if (segA->start != segB->start) {
        return segA->start - segB->start;
    } else {
        return segB->end - segA->end;
    }
}

int main() {
    int n;
    scanf("%d", &n); // 读取线段数量
    Segment* segments = (Segment*)malloc(n * sizeof(Segment));
    for (int i = 0; i < n; i++) {
        scanf("%d,%d", &segments[i].start, &segments[i].end);
        if (segments[i].start > segments[i].end) {
            // 确保起点小于等于终点
            int temp = segments[i].start;
            segments[i].start = segments[i].end;
            segments[i].end = temp;
        }
    }
    
    // 按起点升序排序,如果起点相同,按终点降序排序
    qsort(segments, n, sizeof(Segment), compare);
    
    int count = 0; // 最少线段数量
    int current_end = -2147483648; // 当前覆盖的右端点
    int i = 0;
    
    while (i < n) {
        if (segments[i].start > current_end) {
            // 找到所有起点 <= segments[i].start 的线段中终点最大的
            int max_end = segments[i].end;
            int j = i + 1;
            while (j < n && segments[j].start <= segments[i].start) {
                if (segments[j].end > max_end) {
                    max_end = segments[j].end;
                }
                j++;
            }
            count++;
            current_end = max_end;
            i = j;
        } else {
            // 找到所有起点 <= current_end 的线段中终点最大的
            int max_end = current_end;
            while (i < n && segments[i].start <= current_end) {
                if (segments[i].end > max_end) {
                    max_end = segments[i].end;
                }
                i++;
            }
            if (max_end > current_end) {
                count++;
                current_end = max_end;
            } else {
                i++;
            }
        }
    }
    
    printf("%d\n", count);
    free(segments);
    return 0;
}

九、C++算法源码

#include <bits/stdc++.h>
using namespace std;

// 定义线段结构体
struct Segment {
    int start;
    int end;
};

// 比较函数,用于排序
bool compareSegments(const Segment &a, const Segment &b) {
    if (a.start != b.start)
        return a.start < b.start;
    else
        return a.end > b.end;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n;
    cin >> n; // 读取线段数量
    vector<Segment> segments(n);
    for(int i=0;i<n;i++){
        char comma;
        cin >> segments[i].start >> comma >> segments[i].end;
        if(segments[i].start > segments[i].end){
            swap(segments[i].start, segments[i].end); // 确保起点小于等于终点
        }
    }
    
    // 按起点升序排序,如果起点相同,按终点降序排序
    sort(segments.begin(), segments.end(), compareSegments);
    
    int count = 0; // 最少线段数量
    int current_end = INT32_MIN; // 当前覆盖的右端点
    int i = 0;
    
    while(i < n){
        if(segments[i].start > current_end){
            // 找到所有起点 <= segments[i].start 的线段中终点最大的
            int max_end = segments[i].end;
            int j = i + 1;
            while(j < n && segments[j].start <= segments[i].start){
                if(segments[j].end > max_end){
                    max_end = segments[j].end;
                }
                j++;
            }
            count++;
            current_end = max_end;
            i = j;
        }
        else{
            // 找到所有起点 <= current_end 的线段中终点最大的
            int max_end = current_end;
            while(i < n && segments[i].start <= current_end){
                if(segments[i].end > max_end){
                    max_end = segments[i].end;
                }
                i++;
            }
            if(max_end > current_end){
                count++;
                current_end = max_end;
            }
            else{
                i++;
            }
        }
    }
    
    cout << count << "\n";
    return 0;
}


🏆下一篇:华为OD机试真题 - 简易内存池(Python/JS/C/C++ 2024 E卷 200分)

🏆本文收录于,华为OD机试真题(Python/JS/C/C++)

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。

在这里插入图片描述

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

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

相关文章

二叉树的创建、遍历及销毁

头文件&#xff1a;link_tree.h #ifndef __LINK_TREE_H__ #define __LINK_TREE_H__ #include <stdio.h> #include <stdlib.h> typedef char datatype;//类型重定义 typedef struct tree_node {datatype data;//数据域&#xff0c;存储数据struct tree_node *left;…

【C++前缀和】1895. 最大的幻方|1781

本文涉及的基础知识点 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 LeetCode1895. 最大的幻方 难度分&#xff1a;1781 一个 k x k 的 幻方 指的是一个 k x k 填满整数的方格阵&#xff0c;且每一行、每一列以及两条对角线的和 全部相…

SpringBoot平台:古典舞爱好者的在线聚集地

第三章 系统分析 3.1 可行性分析 需要使用大部分精力开发的古典舞在线交流平台为了充分降低开发风险&#xff0c;特意在开发之前进行可行性分析这个验证系统开发是否可行的步骤。本文就会从技术角度&#xff0c;经济角度&#xff0c;还有操作角度等进行综合阐述。 3.1.1技术可行…

rkllm板端推理

交叉编译 在完成模型的量化构建后&#xff0c;就能够在目标硬件平台OK3576上实现模型的推理功能了。 板端推理的示例代码位于kllm-runtime/examples/rkllm_api_demo目录中&#xff0c;该目录提供了针对Android和Linux平台的编译示例。由于我们的开发环境是基于Linux的&#x…

程序猿成长之路之设计模式篇——设计模式简介

无论是对于代码质量还是代码可维护性、可扩展性&#xff0c;使用合适的设计模式都能够起到促进提升的作用&#xff0c;此外在软考的软件工程师、系统架构师职称考试中&#xff0c;设计模式也是必考的一块内容&#xff0c;因此我打算开拓一个新的专栏简单介绍一下设计模式&#…

数据仓库!企业决策的智慧引擎

数据仓库&#xff01;企业决策的智慧引擎 前言数据仓库 前言 今数字化浪潮汹涌澎湃的时代&#xff0c;数据已然成为企业航行于市场海洋的罗盘&#xff0c;而数据仓库则是那承载罗盘的坚固船只。当我们深入探究数据仓库的世界&#xff0c;就仿佛打开了一扇通往企业智慧核心的大…

Gazebo环境下开源UAV与USV联合仿真平台

推荐一个ROS2下基于Gazebo环境的开源UAV与USV联合仿真平台。平台是由两个开源项目共同搭建的。首先是UAV仿真平台&#xff0c;是基于PX4官方仿真平台&#xff08;https://docs.px4.io/main/en/sim_gazebo_gz&#xff09;&#xff1b;其次是USV仿真平台&#xff0c;是基于VRX仿真…

C++语言学习(4): identifier 的概念

1. 什么是 identifier identifier 中文意思是标识符&#xff0c;在 cppreference 中明确提到&#xff0c;identifier 是任意长度的数字、下划线、大写字母、小写字母、unicode 字符 的序列&#xff1a; An identifier is an arbitrarily long sequence of digits, underscores…

FBX福币历史重演,ETH可能会在第四季度出现熊市

知名加密货币分析师Benjamin Cowen警告称&#xff0c;以太坊(ETH)可能在今年最后三个月突然转为看跌。FBX福币凭借用户友好的界面和对透明度的承诺,迅速在加密货币市场中崭露头角,成为广大用户信赖的平台。 考恩告诉他在社交媒体平台十、上的861500名粉丝表示&#xff0c;ETH可…

240 搜索二维矩阵 II

解题思路&#xff1a; \qquad 解这道题最重要的是如何利用从左到右、从上到下为升序的性质&#xff0c;快速找到目标元素。 \qquad 如果从左上角开始查找&#xff0c;如果当前matrix[i][[j] < target&#xff0c;可以向右、向下扩展元素都是升序&#xff0c;但选择哪个方向…

Python+Matplotlib创建高等数学上册P2页例2交互动画

import numpy as np import matplotlib.pyplot as plt from matplotlib.widgets import Slider, CheckButtons# 创建图形和坐标轴 fig, ax plt.subplots(figsize(10, 8)) plt.subplots_adjust(left0.1, bottom0.2)# 设置图表 ax.set_xlim([-1.5, 1.5]) ax.set_ylim([-1.5, 1.5…

C(九)while循环 --- 军训匕首操情景

匕首操&#xff0c;oi~oi~oi~~~~~ 接下来的几篇推文&#xff0c;杰哥记录的是三大循环结构的运行流程及其变式。 本篇的主角是while循环。&#x1f449; 目录&#xff1a; while循环 的组成、运行流程及其变式关键字break 和 continue 在while 循环中的作用while 循环的嵌套题目…

MySQL中NULL值是否会影响索引的使用

MySQL中NULL值是否会影响索引的使用 为何写这一篇文章 &#x1f42d;&#x1f42d;在面试的时候被问到NULL值是否会走索引的时候&#xff0c;感到有点不理解&#xff0c;于是事后就有了这篇文章 问题&#xff1a; 为name建立索引&#xff0c;name可以为空select * from user …

SpringBoot线程问题

程序&#xff0c;线程&#xff0c;线程池 进程是资源分配最小单位&#xff0c;线程是程序执行的最小单位。计算机在执行程序时&#xff0c;会为程序创建相应的进程&#xff0c;进行资源分配时&#xff0c;是以进程为单位进行相应的分配&#xff0c;每个进程都有相应的线程&…

TiDB 7.x 源码编译之 TiFlash 篇

本文首发于TiDB社区专栏&#xff1a;https://tidb.net/blog/5f3fe44d 导言 TiFlash 从去年四月一日开源至今已经过去将近一年半&#xff0c;这段时间里 TiFlash 从 v6.0.0-DMR 升级到了 v7.3.0-DMR&#xff0c;并增加了若干新特性&#xff0c;比如支持 MPP 实现窗口函数框架&am…

sql-labs靶场第五关测试报告

目录 一、测试环境 1、系统环境 2、使用工具/软件 二、测试目的 三、操作过程 1、寻找注入点 2、注入数据库 ①Order by判断列数 ②寻找注入方式 ③爆库&#xff0c;查看数据库名称 ④爆表&#xff0c;查看security库的所有表 ⑤爆列&#xff0c;查看users表的所有…

Linux之实战命令25:xargs应用实例(五十九)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a; 多媒体系统工程师系列【…

深度优先搜索:解锁无向图连通分量的编号策略

深度优先搜索:解锁无向图连通分量的编号策略 步骤:伪代码:C 代码实现:说明:在无向图中,深度优先搜索(DFS)是一种有效的算法,可以用来找出图的连通分量(Connected Components)。DFS 遍历图的过程中,可以自然地将图划分为若干棵树,这些树构成深度优先森林,其中每棵…

day03 笔试练习

1.简写单词 题目链接&#xff1a;简写单词_牛客题霸_牛客网 public static void main(String[] args) {Scanner sc new Scanner(System.in);while(sc.hasNext()){ // 输入多少读入多少char ch sc.next().charAt(0); // 提取首字母if(ch > a && ch < z){System…

netty之SpringBoot+Netty+Elasticsearch收集日志信息数据存储

前言 将大量的业务以及用户行为数据存储起来用于分析处理&#xff0c;但是由于数据量较大且需要具备可分析功能所以将数据存储到文件系统更为合理。尤其是一些互联网高并发级应用&#xff0c;往往数据库都采用分库分表设计&#xff0c;那么将这些分散的数据通过binlog汇总到一个…