华为OD机考算法题:最小数量线段覆盖

news2024/11/24 3:47:14

目录

题目部分

解读与分析

代码实现


题目部分

题目最小数量线段覆盖
难度
题目说明给定坐标轴(一维坐标轴)上的一组线段,线段的起点和终点均为整数并且长度不小于1,请你从中找到最少数量的线段,这些线段可以覆盖住所有线段。
输入描述第一行输入为所有线段的数量,不超过 10000,后面每行表示一条线段,格式为”x,y",x 和 y 分别表示起点和终点,取值范围是 [-10^{5},10^{5}]。
输出描述最少线段数量,为正整数。
补充说明
------------------------------------------------------
示例
示例1
输入3
1,4
2,5

3,6
输出2
说明选取 2 条线段 [ 1,4 ] 和 [ 3,6 ],这两条线段可以覆盖 [ 2,5 ]。


解读与分析

题目解读

在一个一维坐标系中,有很多线段(通过起止点标识),在求出这些线段覆盖的范围之外,求这些线段中至少可以取几个就能覆盖这些范围。

分析与思路

在解答此题之前,先澄清一下,这些线段覆盖的范围可能是间断的区间。如 3 条线段 [1,4]、[2,5]、[6,7] 覆盖的区间是 [1,5]、[6,7]。

解答此题分三步:排序、分段、回溯。
1. 排序。对所有的线段排序。排序规则为,先对线段的起点进行排序,从小到大;如果起点相等,则对终点排序,也是从小到大。
2. 分段。在前文提到,这些线段覆盖的范围可能是间断的区间。所谓分段,就是找出这些间断的区间。
逐一遍历线段,如果后一个线段的起点大于前一个线段的终点,那么后一个线段就与前一个线段在不同的区间;否则,后一个线段一定与迁移线段处于同一个区间中。
所有位于不同区间的线段绝不会相交,因此,不同分段区间的线段可以单独统计,最后把所有区间的线段之和相加即可。
3. 回溯。对每个单独的区间,使用回溯算法,通过穷举得出所有可能覆盖的情况,从所有的情况中找出所需线段最小的情况。回溯可以使用递归实现,容易理解。

此题时间复杂度为 O(n^{2}),空间复杂度为 O(n)。


代码实现

Java代码

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Scanner;

/**
 * 最少线段覆盖
 * 
 * @since 2023.09.23
 * @version 0.1
 * @author Frank
 *
 */
public class MinLineCount {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		while (sc.hasNext()) {
			String input = sc.nextLine();
			int count = Integer.parseInt(input);

			List<int[]> lines = new ArrayList<>();
			for (int i = 0; i < count; i++) {
				input = sc.nextLine();
				String[] strStartEnd = input.split(",");
				int[] startEnd = new int[2];
				startEnd[0] = Integer.parseInt(strStartEnd[0]);
				startEnd[1] = Integer.parseInt(strStartEnd[1]);
				lines.add(startEnd);
			}
			processMinLineCount( lines);
		}
	}

	private static void processMinLineCount( List<int[]> lines) {
		// 1. 排序
		Comparator<int[]> cmp = new Comparator<int[]>() {
			@Override
			public int compare(int[] o1, int[] o2) {
				for (int i = 0; i < o1.length; i++) {
					if (o1[i] != o2[i]) {
						return o1[i] - o2[i];
					}
				}
				return 0;
			}
		};

		lines.sort(cmp);

		// 2. 分段
		class LinePart {
			int start; // 起始点,包含在内
			int end; // 终止点,包含在内
			int startIdx; // 对应lines中的起始下标,包含在内
			int endIdx; // 对应lines中的终止下标,包含在内
		}

		List<LinePart> lpList = new ArrayList<LinePart>();
		LinePart tmpLP = new LinePart();
		for (int i = 0; i < lines.size(); i++) {
			int[] tmpLine = lines.get(i);
			if (i == 0) {
				tmpLP.start = tmpLine[0];
				tmpLP.end = tmpLine[1];
				tmpLP.startIdx = 0;
				tmpLP.endIdx = 0;
				lpList.add( tmpLP );
				continue;
			}
			
			// 不是同一个区间
			if( tmpLine[0] > tmpLP.end )
			{
				tmpLP = new LinePart();
				tmpLP.start = tmpLine[0];
				tmpLP.end = tmpLine[1];
				tmpLP.startIdx = i;
				tmpLP.endIdx = i;
				lpList.add( tmpLP );
				continue;
			}else  // 同一个区间
			{
				tmpLP.end = tmpLine[1];
				tmpLP.endIdx = i;
			}
			
		}
		
		//3.逐段求和
		int count = 0;
		for( int i = 0; i < lpList.size(); i ++ )
		{
			LinePart lpPart = lpList.get( i );
			List<int[]> tmpList = new ArrayList<int[]>();
			for( int j = lpPart.startIdx; j <= lpPart.endIdx; j ++ )	//  j <= lpPart.endIdx,包含在内
			{
				int[] tmpLine = lines.get( j );
				int[] copy = new int[2];
				copy[0] = tmpLine[0];
				copy[1] = tmpLine[1];
				tmpList.add( copy );
			}
			int partCount = getPartMinCount( tmpLP.start, tmpLP.end, tmpList );
			count += partCount;
		}
		System.out.println( count );

	}
	
	private static int getPartMinCount( int start, int end, List<int[]> list)
	{
		if( start >= end )
		{
			return 0;
		}
		int minCount = list.size();
		for( int i = 0; i < list.size(); i ++ )
		{
			int tmpCount = 0;
			int[] cur = list.get( i );
			
			// 当它已经无法覆盖
			if( cur[0] > start )
			{
				break;
			}
			
			// 如果end小于start,那这样的线段根本不需要
			if( cur[1] < start  )
			{
				continue;
			}
			
			list.remove( i );
			
			tmpCount ++;
			tmpCount += getPartMinCount( cur[1], end, list);
			
			list.add( i, cur );
			if( tmpCount < minCount )
			{
				minCount = tmpCount;
			}
		}
		
		return minCount;
	}
}

JavaScript代码

const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
void async function() {
    while (line = await readline()) {
        var count = parseInt(line);

        var lines = new Array();
        for (var i = 0; i < count; i++) {
            line = await readline();
            var strStartEnd = line.split(",");
            var startEnd = [];
            startEnd[0] = parseInt(strStartEnd[0]);
            startEnd[1] = parseInt(strStartEnd[1]);
            lines[i] = startEnd;
        }

        processMinLineCount(lines);
    }
}();

function compareLineFun(a, b) {
    for (var i = 0; i < a.length; i++) {
        if (a[i] != b[i]) {
            return a[i] - b[i];
        }
    }
    return 0;
}

function processMinLineCount(lines) {
    // 1. 排序
    lines.sort(compareLineFun);

    // 2. 分段

    // LinePart 的数据结构
    // LinePart  {
    //      start; // 起始点,包含在内
    //      end; // 终止点,包含在内
    //      startIdx; // 对应lines中的起始下标,包含在内
    //      endIdx; // 对应lines中的终止下标,包含在内
    //  }

    var lpList = new Array();
    var tmpLP = {};
    for (var i = 0; i < lines.length; i++) {
        var tmpLine = lines[i];
        if (i == 0) {
            tmpLP.start = tmpLine[0];
            tmpLP.end = tmpLine[1];
            tmpLP.startIdx = 0;
            tmpLP.endIdx = 0;
            lpList.push(tmpLP);
            continue;
        }

        // 不是同一个区间
        if (tmpLine[0] > tmpLP.end) {
            tmpLP = new LinePart();
            tmpLP.start = tmpLine[0];
            tmpLP.end = tmpLine[1];
            tmpLP.startIdx = i;
            tmpLP.endIdx = i;
            lpList.push(tmpLP);
            continue;
        } else // 同一个区间
        {
            tmpLP.end = tmpLine[1];
            tmpLP.endIdx = i;
        }

    }

    //3.逐段求和
    var count = 0;
    for (var i = 0; i < lpList.length; i++) {
        var lpPart = lpList[i];
        var tmpList = new Array();
        for (var j = lpPart.startIdx; j <= lpPart.endIdx; j++) //  j <= lpPart.endIdx,包含在内
        {
            var tmpLine = lines[j];
            var copy = [];
            copy[0] = tmpLine[0];
            copy[1] = tmpLine[1];
            tmpList.push(copy);
        }
        var partCount = getPartMinCount(tmpLP.start, tmpLP.end, tmpList);
        count += partCount;
    }
    console.log(count);
}

function getPartMinCount(start, end, list) {
    if (start >= end) {
        return 0;
    }
    var minCount = list.length;
    for (var i = 0; i < list.length; i++) {
        var tmpCount = 0;
        var cur = list[i];

        // 当它已经无法覆盖
        if (cur[0] > start) {
            break;
        }

        // 如果end小于start,那这样的线段根本不需要
        if (cur[1] < start) {
            continue;
        }

        list.splice(i, 1);

        tmpCount++;
        tmpCount += getPartMinCount(cur[1], end, list);

        list.splice(i, 0, cur);
        if (tmpCount < minCount) {
            minCount = tmpCount;
        }
    }

    return minCount;
}

此题难度有些大,从思考算法,到实现代码并通过测试,都有不少工作量。在华为 OD 考题中,属于难度较大的题。

(完)

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

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

相关文章

基于微信小程序的社区垃圾回收管理系统设计与实现

文章目录 前言系统主要功能&#xff1a;具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…

Eclipse安装sts插件(eclipse 内置应用市场无法搜索到sts时)

下面提供一个可以通过help->install new software->add添加外部sts&#xff08;spring tool suite&#xff09;插件&#xff0c;springplugins - https://download.springsource.com/release/TOOLS/update/e4.12/ 官网(https://spring.io/tools3/sts/all)可以下载不同的…

Nodejs基于Vue.js博物馆预约系统7e122

博物馆展览与服务一体化&#xff0c;其工作流程繁杂、多样、管理复杂与设备维护繁琐。而计算机已完全能够胜任博物馆展览与服务一体化工作&#xff0c;而且更加准确、方便、快捷、高效、清晰、透明&#xff0c;它完全可以克服以上所述的不足之处。这将给查询信息和管理带来很大…

Spring Boot 中的 CSRF 保护配置

Spring Boot 中的 CSRF 保护配置 CSRF&#xff08;Cross-Site Request Forgery&#xff09;是一种网络攻击&#xff0c;它利用已认证用户的身份来执行未经用户同意的操作。Spring Boot 提供了内置的 CSRF 保护机制&#xff0c;可以帮助您防止这种类型的攻击。本文将介绍如何在…

ArduPilot开源飞控之GCS显示DPS310异常问题

ArduPilot开源飞控之GCS显示DPS310异常问题 1. 源由2. 现象3. 分析3.1 Mission Planner3.2 Ardupilot3.3 AP_Baro分析3.4 AP_Baro定位 4. 修复5. 效果6. 参考资料7. 补充7.1 Ardupilot提交PR注意事项7.2 修复主要使用到的命令 1. 源由 2020年Ardupilot官网论坛就有开始讨论DPS…

CompletableFuture-链式语法和join方法介绍

2.4 案例精讲-从电商网站的比价需求展开 2.4.1 函数式编程已成为主流 Lambda表达式Stream流式调用Chain链式调用Java8函数式编程 函数式接口&#xff1a; 小结&#xff1a; 函数式接口&#xff1a; Java8新特性_四大内置核心函数式接口_java8 内置核心接口_ZHOU_VIP的博客-…

idea没有maven工具栏解决方法

背景&#xff1a;接手的一些旧项目&#xff0c;有pom文件&#xff0c;但是用idea打开的时候&#xff0c;没有认为是maven文件&#xff0c;所以没有maven工具栏&#xff0c;不能进行重新加载pom文件中的依赖。 解决方法&#xff1a;选中pom.xml文件&#xff0c;右键 选择添加为…

华为乾坤区县教育安全云服务解决方案(1)

华为乾坤区县教育安全云服务解决方案&#xff08;1&#xff09; 课程地址方案背景客户痛点分析区县教育网概述区县教育网业务概述区县教育网业务安全风险分析区县教育网安全运维现状分析区县教育网安全建设痛点分析 安全解决方案功能概述架构概述方案架构设备选型 课程地址 本…

mysql的锁分类:表锁和行锁和页面锁

一 锁的概念 1.1 锁的作用 锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中&#xff0c;除传统的计算资源&#xff08;如CPU、RAM、I/O等&#xff09;的争用以外&#xff0c;数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有…

难点解释-理解寄主机通过虚拟网络连接到虚拟机的概念

“寄主机”通过“虚拟网络”连接“虚拟机”的关键点Brainstorm 获得“虚拟机”的ip地址 ip a 确保“寄主机”能ping通“虚拟机” SSH客户端连接虚拟机 SSH客户端有很多&#xff0c;这里用的是XSHELL Q&A SSH连接提示超时 表明寄主机到虚拟机的网络没有通&#xff0c;检…

实现数据库用户校验

导入my-batis-plus依赖&#xff1a; <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </depende…

【图论C++】链式前先星(图(树)的存储)

/*** file * author jUicE_g2R(qq:3406291309)————彬(bin-必应)* 一个某双流一大学通信与信息专业大二在读 * * brief 一直在竞赛算法学习的路上* * copyright 2023.9* COPYRIGHT 原创技术笔记&#xff1a;转载需获得博主本人…

Flink--6、输出算子(连接到外部系统、文件、kafka、MySQL、自定义Sink)

星光下的赶路人star的个人主页 世间真正温煦的春色&#xff0c;都熨帖着大地&#xff0c;潜伏在深谷 文章目录 1、输出算子&#xff08;Sink&#xff09;1.1 连接到外部系统1.2 输出到文件1.3 输出到Kafka1.4 输出到MySQL&#xff08;JDBC&#xff09;1.4 自定义Sink输出 1、输…

Unity插件Xcharts3.x版本使用笔记

Unity插件Xcharts3.x版本使用笔记 官方下载链接&#xff1a;https://xcharts-team.github.io/导入Unity基本使用方式&#xff08;折线图动态添加数据&#xff09;如果想要更多的表现效果可以看官方自带的脚本&#xff0c;这里包括了官方展示案例的部分效果&#xff0c;不过没有…

Windows10操作系统部署AD

windows 10 安装配置AD 一、启用AD 1.打开控制面板—>程序—>启用或关闭windows功能 2.勾选Active Directory Lightweight Directory Services&#xff08;Active Directory 轻型目录服务&#xff09; 注&#xff1a;不同版本中英文显示有区别&#xff0c;认准AD字样就…

Learn Prompt- Midjourney案例:动漫设计

使用 Midjourney 生成动漫有两种方法&#xff1a;使用Niji模式或使用标准的 Midjourney 模型。Niji V5 是 Midjourney 的动漫专用模型。它建立在标准 Midjourney 模型的全新架构之上&#xff0c;更擅长生成命名的动漫角色。Niji V4于2023年12月发布&#xff0c;Niji V5于2023年…

uniapp中使用axios打包到小程序时报 TypeError: adapter is not a function

出现这个错误的原因是因为小程序支持的是它自己原生封装的request接口&#xff0c;它底层用的http的。 若需要使用axios的话&#xff0c;我们需要使用一个axios适配器来兼容小程序。 下面用到axios-miniprogram-adapter适配器来解决 gitHub地址&#xff1a;GitHub - bigmeow…

智能中充满了符号、逻辑、力的想象和诱惑

把智能仅仅视为物化的理性特征符号的观点忽略了智能的社会性和交互性。智能不仅仅是个体内部的智能表现&#xff0c;还包括人与人之间的互动和人机环境系统的影响。智能是人类与其环境相互作用的结果&#xff0c;受到社会文化、教育、经验等因素的影响&#xff0c;具有社会意义…

域名备案流程(个人备案,腾讯云 / 阿里云)

文章目录 1.网站备案的目的2.备案准备的材料2.1 网站域名2.2 云资源或备案授权码2.3 电子材料 3.首次个人备案准备的材料3.1 主体相关3.2 域名相关3.3 网站相关3.4 网站服务相关3.5 变更相关 4.个人备案流程4.1 登录系统4.2 填写备案信息&#x1f340; 填写备案省份&#x1f34…

sql防止连表查询后出现空行数据

sql防止连表查询后出现空行数据 防止连表查询后出现空行数据 1.在where后加&#xff1a;and t2.pk_id is not null 或者2.在返回值list上处理 List TaskItem intelligentCloudMapper.getTaskItem(params.getPkId()); TaskItem.removeAll(Collections.singleton(null)); <se…