news 2026/4/16 8:40:55

(新卷,200分)- 区间交叠问题(Java JS Python)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
(新卷,200分)- 区间交叠问题(Java JS Python)

(新卷,200分)- 区间交叠问题(Java & JS & Python)

题目描述

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

输入描述

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

输出描述

最少线段数量,为正整数

用例
输入

3
1,4
2,5
3,6

输出2
说明
题目解析

用例1图示如下

可以发现,只要选择[]1,4[和[3,6]就可以覆盖住所有给定线段。

我的解题思路如下:

首先,将所有区间ranges按照开始位置升序。

然后,创建一个辅助的栈stack,初始时将排序后的第一个区间压入栈中。

然后,遍历出1~ranges.length范围内的每一个区间ranges[i],将遍历到ranges[i]和stack栈顶区间对比:

  • 如果stack栈顶区间可以包含ranges[i]区间,则range[i]不压入栈顶
  • 如果stack栈顶区间被ranges[i]区间包含,则弹出stack栈顶元素,继续比较ranges[i]和stack新的栈顶元素
  • 如果stack栈顶区间和ranges[i]无法互相包含,只有部分交集,则将ranges[i]区间去除交集部分后,剩余部分区间压入stack
  • 如果stack栈顶区间和ranges[i]区间没有交集,那么直接将ranges[i]压入栈顶

这样的话,最终stack中有多少个区间,就代表至少需要多少个区间才能覆盖所有线段。

比如,用例1的运行流程如下:

2,5 和 1,4 存在重叠区间,我们只保留2,5区间的非重叠部分4,5

比较4,5区间和3,6区间,发现3,6完全涵盖2,5,因此2,5区间不再需要,可以从stack中弹栈删掉,即原始的2,5区间被删除了。

继续比较1,4和3,6区间,发现无法互相涵盖,因此都需要保留,但是3,6有部分区间和1,4重叠,因此只保留3,6不重叠部分4,6。

最终只需要两个区间,对应1,4、3,6,即可涵盖所有线段

自测用例:

8
0,4
1,2
1,4
3,7
6,8
10,12
11,13
12,14

输出5,即至少需要上面标红的五个区间才能覆盖所有线段。


2023.01.27

根据网友指正,上面逻辑缺失一个场景,比如:

3

1,10

5,12

8,11

按找前面逻辑,首先对所有区间按开始位置升序,然后将1,10入栈

然后尝试将5,12入栈,发现和栈顶区间有交集,因此去除交集部分后,5,12变为10,12,入栈

然后尝试将8,11入栈,但是此时出现一个尴尬的情况,那就是栈顶区间10,12不能完全包含8,11,因此8,11区间还需要和栈顶前一个区间1,10继续比较,这就背离了我们一开始将所有区间按开始位置升序的初衷了。。。

而导致这个问题的根本原因是,栈顶区间10,12是被裁剪过的,因此导致它的起始位置落后了,即可能无法包含住升序后下一个区间的起始位置了,但是转念一想,先入栈的区间的起始位置肯定是要小于等于后入栈的区间的,因此栈顶区间被裁剪,说明栈顶区间和前一个区间必然是严密结合的,因此8,11的起始位置超出了栈顶区间,其实还是会被栈顶前一个区间包含进去。因此这里8,11不入栈。

JavaScript算法源码
/* JavaScript Node ACM模式 控制台输入获取 */ const readline = require("readline"); const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); const lines = []; let n; rl.on("line", (line) => { lines.push(line); if (lines.length === 1) { n = lines[0] - 0; } if (n && lines.length === n + 1) { lines.shift(); const ranges = lines.map((line) => line.split(",").map(Number)); console.log(getResult(ranges, n)); lines.length = 0; } }); function getResult(ranges, n) { ranges.sort((a, b) => a[0] - b[0]); const stack = [ranges[0]]; for (let i = 1; i < ranges.length; i++) { const range = ranges[i]; while (true) { if (stack.length == 0) { stack.push(range); break; } const [s0, e0] = stack.at(-1); const [s1, e1] = range; if (s1 <= s0) { if (e1 <= s0) { break; } else if (e1 < e0) { break; } else { stack.pop(); } } else if (s1 < e0) { if (e1 <= e0) { break; } else { stack.push([e0, e1]); break; } } else { stack.push(range); break; } } } //console.log(stack); return stack.length; }
Java算法源码
import java.util.Arrays; import java.util.LinkedList; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = Integer.parseInt(sc.nextLine()); Integer[][] ranges = new Integer[n][]; for (int i = 0; i < n; i++) { ranges[i] = Arrays.stream(sc.nextLine().split(",")).map(Integer::parseInt).toArray(Integer[]::new); } System.out.println(getResult(ranges)); } public static int getResult(Integer[][] ranges) { Arrays.sort(ranges, (a, b) -> a[0] - b[0]); LinkedList<Integer[]> stack = new LinkedList<>(); stack.add(ranges[0]); for (int i = 1; i < ranges.length; i++) { Integer[] range = ranges[i]; while (true) { if (stack.size() == 0) { stack.add(range); break; } Integer[] top = stack.getLast(); int s0 = top[0]; int e0 = top[1]; int s1 = range[0]; int e1 = range[1]; if (s1 <= s0) { if (e1 <= s0) { break; } else if (e1 < e0) { break; } else { stack.removeLast(); } } else if (s1 < e0) { if (e1 <= e0) { break; } else { stack.add(new Integer[] {e0, e1}); break; } } else { stack.add(range); break; } } } return stack.size(); } }
Python算法源码
# 输入获取 n = int(input()) rans = [list(map(int, input().split(","))) for i in range(n)] # 算法入口 def getResult(rans, n): rans.sort(key=lambda x: x[0]) stack = [rans[0]] for i in range(1, n): ran = rans[i] while True: if len(stack) == 0: stack.append(ran) break s0, e0 = stack[-1] s1, e1 = ran if s1 <= s0: if e1 <= s0: break elif e1 < e0: break else: stack.pop() elif s1 < e0: if e1 <= e0: break else: stack.append([e0, e1]) break else: stack.append(ran) break return len(stack) # 算法调用 print(getResult(rans, n))
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/1 17:06:08

蓝莓基质/土壤

蓝莓喜欢酸性土壤&#xff0c;pH在4-5.5之间e 换盆的时候可以加些松针土、泥炭土与原先的土1:1混合。也可以用硫酸亚铁拌土&#xff0c;100g/平方米。平时浇水的时候也可以用1升水兑上1g的硫酸亚铁&#xff0c;每10-15天浇一次。2蓝莓对氯敏感&#xff0c;平时用自来水浇水的时…

作者头像 李华
网站建设 2026/4/11 17:32:56

用Microsoft Visual Studio Installer Projects打包程序

参考https://blog.csdn.net/m0_51961114/article/details/134908822 添加文件方式 方式一&#xff1a;如下图方式&#xff0c;可能有的.dll文件没添加上 方式二&#xff1a;直接按照自己的Debug/Release下所需的文件目录和文件在Application Folder下创建并添加相关文件&…

作者头像 李华
网站建设 2026/4/12 12:20:45

【观成科技】C2框架AdaptixC2加密流量分析

工具介绍 AdaptixC2 是一款设计简洁、灵活且易于定制的命令与控制 (C2) 框架。与复杂且臃肿的大型 C2 平台不同&#xff0c;其轻量级设计使得攻击者能够更轻松地在不同环境中部署和调整。该框架采用模块化设计&#xff0c;支持C2工具的基本功能&#xff0c;例如在受感染的机器…

作者头像 李华
网站建设 2026/4/14 20:54:37

linux Page Table 和 TLB 操作总结

以下是 Linux 内核中与页表和 TLB 操作对应的主要 API/函数列表&#xff0c;结合上述操作分类&#xff1a;页表&#xff08;Page Table&#xff09;相关 API 1. 地址转换操作内核 API/函数说明虚拟地址→物理地址virt_to_phys()、__pa()内核虚拟地址转物理地址物理地址→虚拟地…

作者头像 李华
网站建设 2026/3/26 6:30:57

sparse4D v3

4个技术细节&#xff1a; temporal instance denoising quality estimation decoupled attention extend to tracking 1. Temporal Instance Denoising&#xff08;时序实例去噪&#xff09; 背景问题&#xff08;Sparse4D / v2 中的痛点&#xff09; Sparse4D 系列的核心是 …

作者头像 李华