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

在这里插入图片描述

华为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在线答疑。

在这里插入图片描述

华为OD机试 - 处理器问题。 在华为OD机试中,处理器问题是其中一个重要的内容。处理器是计算机系统的核心组件,负责执行所有的计算任务和指令。以下是对处理器问题的回答: 处理器是一种位于计算机内部的电子设备,它负责从内存中获取指令和数据,并执行这些指令。处理器的性能直接影响计算机的整体运行速度和效率。在华为OD机试中,处理器问题可能涉及到以下几个方面: 1. 处理器的种类和架构:处理器的种类包括单核、双核、四核等不同型号和规格的处理器。不同种类的处理器采用了不同的架构设计,如ARM、x86等。应根据具体的问题了解各种处理器的特点和适用场景。 2. 处理器的性能参数:处理器的性能可以通过多种指标来评估,如主频、核心数、缓存大小、功耗等。在处理器问题中,可能需要对处理器的性能参数进行析和比较,来选择合适的处理器。 3. 处理器的调度算法:在多任务环境下,处理器需要根据不同的调度算法来配资源和管理任务。例如,可以采用先来先服务、时间片轮转等调度算法。处理器问题可能会涉及到如何选择合适的调度算法,以提高系统的整体性能。 4. 处理器的优化技术:为了提高处理器的性能和效率,可以采用一系列的优化技术。例如,使用流水线、超标量、超线程等技术来提高指令并行度;使用缓存技术来提高内存访问速度等。处理器问题可能需要对这些优化技术进行了解和应用。 综上所述,处理器问题华为OD机试中一个重要的内容,需要对处理器的种类、架构、性能参数、调度算法以及优化技术进行了解和应用。只有掌握了这些知识,才能在处理器问题中做出准确的判断和正确的选择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哪 吒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值