
华为OD机试 新系统 题库疯狂收录中,刷题点这里
专栏导读
本专栏收录于《华为OD机试(JAVA)真题》。
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天优快云在线答疑。
一、题目描述
给定一个以二维数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi](starti 和 endi 都是整数),这些区间之间可能存在重叠,请统计跟其他任何区间都不重叠的区间数量。
二、输入描述
一个二维数组 intervals,每一行输入对应intervals[i], 。 intervals[i] 表示第 i 个区间,intervals[i][0] 表示第 i 个区间的 starti,intervals[i][1] 表示第 i 个区间的 endi。
三、输出描述
这个区间集合中跟其他区间都不重叠的区间数量。
补充说明:
-
1 ≤ intervals.length ≤ 10000
-
intervals[i].length == 2
-
0 ≤ starti ≤ endi ≤ 10000
四、测试用例
测试用例1:
1、输入
8 10
1 4
2 6
15 18
2、输出
2
3、说明
排序后为:
[1,4]
[2,6]
[8,10]
[15,18]
[1,4] 和 [2,6] 重叠。
[8,10]、[15,18] 均没有和其他区间重叠,因此答案为 2。
测试用例2:
1、输入
2 4
4 6
2、输出
0
3、说明
两个区间在端点 4 相交,根据题目给出的预期结果,这种情况也属于重叠,因此不存在孤立区间。
五、解题思路
如果直接让每个区间和其他所有区间进行比较,需要两层循环,时间复杂度为 O(n²)。题目中区间数量最多为 10000,虽然不一定超时,但没有必要进行如此多的重复比较。
更合适的方法是先按照区间的起点从小到大排序,然后从左向右进行一次扫描。
维护两个变量:currentEnd 表示当前这一组相互连接的重叠区间能够到达的最右端点,currentGroupSize 表示当前重叠组中有多少个区间。
对于排序后的下一个区间 [start, end]:
- 如果
start <= currentEnd,说明它与当前重叠组存在交集。由于题目测试用例表明端点相等也算重叠,因此这里必须使用<=。此时更新currentEnd = max(currentEnd, end),并将组内区间数量加一。 - 如果
start > currentEnd,说明当前区间与之前的重叠组完全分离。此时检查上一组:如果currentGroupSize == 1,说明上一组只有一个区间,它没有和任何其他区间发生重叠,因此答案加一。随后以当前区间建立新的重叠组。
扫描结束后,再结算最后一个重叠组即可。
本题使用动态数组保存所有区间,排序后使用贪心/扫描线思想处理。排序时间复杂度为 O(n log n),扫描时间复杂度为 O(n),因此总时间复杂度为 O(n log n),空间复杂度为 O(n)。
六、Java算法源码
public class OdTest {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
List<int[]> intervals = new ArrayList<>();
/*
* 题目没有单独给出区间数量 n,
* 因此按照“每两个整数表示一个区间”的方式一直读取到 EOF。
*/
while (scanner.hasNextLine()) {
String input = scanner.nextLine();
if(input.isEmpty()){
break;
}
String[] arr = input.split(" ");
intervals.add(new int[]{Integer.valueOf(arr[0]), Integer.valueOf(arr[1])});
}
if (intervals.isEmpty()) {
System.out.println(0);
return;
}
/*
* 按区间起点从小到大排序。
* 如果起点相同,再按照终点从小到大排序,
* 这样就可以从左到右一次扫描所有区间。
*/
intervals.sort(Comparator
.comparingInt((int[] interval) -> interval[0])
.thenComparingInt(interval -> interval[1]));
int isolatedCount = 0;
// 当前重叠组能够覆盖到的最右端点
int currentEnd = intervals.get(0)[1];
// 当前重叠组包含的区间数量
int currentGroupSize = 1;
for (int i = 1; i < intervals.size(); i++) {
int start = intervals.get(i)[0];
int end = intervals.get(i)[1];
/*
* 如果当前区间起点 <= 当前重叠组的最右端点,
* 说明当前区间和当前组中的某个区间存在重叠。
*
* 注意必须使用 <=:
* 例如 [2,4] 与 [4,6] 在端点 4 处相交,
* 根据题目测试用例,它们属于重叠区间。
*/
if (start <= currentEnd) {
currentEnd = Math.max(currentEnd, end);
currentGroupSize++;
} else {
/*
* 当前区间已经与上一组完全分离。
*
* 如果上一组只有一个区间,则说明这个区间
* 没有和任何其他区间发生过重叠,因此答案加 1。
*/
if (currentGroupSize == 1) {
isolatedCount++;
}
// 从当前区间开始建立一个新的重叠组
currentEnd = end;
currentGroupSize = 1;
}
}
/*
* 循环中只有遇到下一组时才会结算上一组,
* 所以最后一个重叠组需要单独处理。
*/
if (currentGroupSize == 1) {
isolatedCount++;
}
System.out.println(isolatedCount);
}
}
七、效果展示
1、输入
10 10
0 1
5 5
4 5
7 9
2 3
2、输出
4
3、说明
排序后:
[0,1]
[2,3]
[4,5]
[5,5]
[7,9]
[10,10]
其中:
[0,1] 孤立;
[2,3] 孤立;
[4,5] 与 [5,5] 重叠;
[7,9] 孤立;
[10,10] 孤立。
因此答案为 4。

🏆下一篇:华为OD机试 - 简易内存池 - 逻辑分析(Java 新系统 200分)
🏆本专栏收录于《华为OD机试(JAVA)真题》。
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天优快云在线答疑。

10万+



被折叠的 条评论
为什么被折叠?



