统计不重叠区间的个数(C/C++/Py/Java/Js/Go)题解
华为OD机试新系统真题 华为OD上机考试新系统真题 6月28号 100分题型
华为OD机试新系统真题目录点击查看: 华为OD机试新系统真题题库目录|机考题库 + 算法考点详解
题目内容
给定一个以二维数组 intervals \text{intervals} intervals 表示若干个区间的集合,其中单个区间为 intervals i = starti , endi \text{intervals}i = \\text{starti}, \\text{endi} intervalsi=starti,endi( starti \text{starti} starti 和 endi \text{endi} endi 都是整数),这些区间之间可能存在重叠,请统计跟其他任何区间都不重叠的区间数量。
输入描述
一个二维数组 intervals \text{intervals} intervals,每一行输入对应 intervalsi,。 \text{intervalsi},。 intervalsi,。 intervals i \text{intervals}i intervalsi 表示第 i i i 个区间, intervals i 0 \text{intervals}i0 intervalsi0 表示第 i i i 个区间的 starti \text{starti} starti, intervals i 1 \text{intervals}i1 intervalsi1 表示第 i i i 个区间的 endi \text{endi} endi。
输出描述
这个区间集合中跟其他区间都不重叠的区间数量。
补充说明:
- 1 ≤ intervals.length ≤ 10000 1 \le \text{intervals.length} \le 10000 1≤intervals.length≤10000
- intervals i . l e n g t h = = 2 \text{intervals}i.length == 2 intervalsi.length==2
- 0 ≤ starti ≤ endi ≤ 10000 0 \le \text{starti} \le \text{endi} \le 10000 0≤starti≤endi≤10000
样例1
输入
8 10
1 4
2 6
15 18
输出
2
说明
区间 8 , 10 8,10 8,10 和 15 , 18 15,18 15,18 跟其他区间都不重合
样例2
输入
2 4
4 6
输出
0
说明
2 , 4 2,4 2,4 和 4 , 6 4,6 4,6 这 2 2 2 个区间重叠,不存在跟其他区间都不重叠的区间,故返回 0 0 0
题解
思路:逻辑分析
- 首先对输入区间进行按照
按左端点升序排序,左端点相同按右端点升序排序 - 接下来在考虑发生冲突的情况,
intervals[i]发生重叠的区间情况为- 与左侧区间发生重叠情况为,
[0..i-1]的最大区间end大于等于intervals[i].start - 与右侧区间发生重叠情况为,
[i+1..n-1]的最小区间start小于等于intervals[i].end
- 与左侧区间发生重叠情况为,
- 按照2的分析可以预处理每个位置前缀最大
end和后缀最小start,使用preMax和sufMin保存。 - 接下来进行从前往后遍历,如果
preMax[i-1] < intervals[i].start && sufMin[i+1] > intervals[i].end则结果+1.
C++
cpp
#include<bits/stdc++.h>
#include <vector>
using namespace std;
// 通用 切割函数 函数 将字符串str根据delimiter进行切割
vector<int> split(const string& str, const string& delimiter) {
vector<int> result;
size_t start = 0;
size_t end = str.find(delimiter);
while (end != string::npos) {
result.push_back(stoi(str.substr(start, end - start)));
start = end + delimiter.length();
end = str.find(delimiter, start);
}
// 添加最后一个部分
result.push_back(stoi(str.substr(start)));
return result;
}
int getIsolationInterval(vector<vector<int>>& intervals) {
// 按左端点升序排序,左端点相同按右端点升序排序
sort(intervals.begin(), intervals.end(), [](vector<int>& a, vector<int>& b) {
if (a[0] != b[0]) {
return a[0] < b[0];
}
return a[1] < b[1];
});
int n = intervals.size();
// preMax[i]右端点能取的最大值
vector<int> preMax(n);
preMax[0] = intervals[0][1];;
for (int i = 1; i < n; i++) {
preMax[i] = max(preMax[i - 1], intervals[i][1]);
}
// sufMin[i]左端点能取的最小值
vector<int> sufMin(n);
sufMin[n - 1] = intervals[n - 1][0];
int ans = 0;
for (int i = 0; i < n; i++) {
// 左侧是否冲突
bool leftOverlap = false;
// 右侧是否冲突
bool rightOverlap = false;
if (i > 0 && preMax[i-1] >= intervals[i][0]) {
leftOverlap = true;
}
if (i + 1 < n && sufMin[i+1] <= intervals[i][1]) {
rightOverlap = true;
}
if (!leftOverlap && !rightOverlap) {
ans++;
}
}
return ans;
}
int main() {
vector<vector<int>> intervals;
string input;
while (getline(cin, input)) {
if (input.empty()) {
break;
}
intervals.push_back(split(input, " "));
}
cout << getIsolationInterval(intervals);
return 0;
}
Java
java
import java.util.*;
public class Main {
public static int getIsolationInterval(List<int[]> intervals) {
// 按左端点升序排序,左端点相同按右端点升序排序
intervals.sort((a, b) -> {
if (a[0] != b[0]) {
return Integer.compare(a[0], b[0]);
}
return Integer.compare(a[1], b[1]);
});
int n = intervals.size();
// preMax[i]右端点能取的最大值
int[] preMax = new int[n];
preMax[0] = intervals.get(0)[1];
for (int i = 1; i < n; i++) {
preMax[i] = Math.max(preMax[i - 1], intervals.get(i)[1]);
}
// sufMin[i]左端点能取的最小值
int[] sufMin = new int[n];
sufMin[n - 1] = intervals.get(n - 1)[0];
for (int i = n - 2; i >= 0; i--) {
sufMin[i] = Math.min(sufMin[i + 1], intervals.get(i)[0]);
}
int ans = 0;
for (int i = 0; i < n; i++) {
// 左侧是否冲突
boolean leftOverlap = false;
// 右侧是否冲突
boolean rightOverlap = false;
if (i > 0 && preMax[i - 1] >= intervals.get(i)[0]) {
leftOverlap = true;
}
if (i + 1 < n && sufMin[i + 1] <= intervals.get(i)[1]) {
rightOverlap = true;
}
if (!leftOverlap && !rightOverlap) {
ans++;
}
}
return ans;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
List<int[]> intervals = new ArrayList<>();
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
if (line.isEmpty()) {
break;
}
String[] strs = line.split(" ");
intervals.add(new int[]{
Integer.parseInt(strs[0]),
Integer.parseInt(strs[1])
});
}
System.out.println(getIsolationInterval(intervals));
}
}
Python
python
def getIsolationInterval(intervals):
# 按左端点升序排序,左端点相同按右端点升序排序
intervals.sort(key=lambda x: (x[0], x[1]))
n = len(intervals)
# preMax[i]右端点能取的最大值
preMax = [0] * n
preMax[0] = intervals[0][1]
for i in range(1, n):
preMax[i] = max(preMax[i - 1], intervals[i][1])
# sufMin[i]左端点能取的最小值
sufMin = [0] * n
sufMin[-1] = intervals[-1][0]
for i in range(n - 2, -1, -1):
sufMin[i] = min(sufMin[i + 1], intervals[i][0])
ans = 0
for i in range(n):
# 左侧是否冲突
leftOverlap = False
# 右侧是否冲突
rightOverlap = False
if i > 0 and preMax[i - 1] >= intervals[i][0]:
leftOverlap = True
if i + 1 < n and sufMin[i + 1] <= intervals[i][1]:
rightOverlap = True
if not leftOverlap and not rightOverlap:
ans += 1
return ans
intervals = []
try:
while True:
line = input()
if line == "":
break
intervals.append(list(map(int, line.split())))
except EOFError:
pass
print(getIsolationInterval(intervals))
JavaScript
js
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const intervals = [];
rl.on("line", (line) => {
if (line.trim() !== "") {
intervals.push(line.split(" ").map(Number));
}
});
rl.on("close", () => {
console.log(getIsolationInterval(intervals).toString());
});
function getIsolationInterval(intervals) {
// 按左端点升序排序,左端点相同按右端点升序排序
intervals.sort((a, b) => {
if (a[0] !== b[0]) {
return a[0] - b[0];
}
return a[1] - b[1];
});
const n = intervals.length;
// preMax[i]右端点能取的最大值
const preMax = new Array(n);
preMax[0] = intervals[0][1];
for (let i = 1; i < n; i++) {
preMax[i] = Math.max(preMax[i - 1], intervals[i][1]);
}
// sufMin[i]左端点能取的最小值
const sufMin = new Array(n);
sufMin[n - 1] = intervals[n - 1][0];
for (let i = n - 2; i >= 0; i--) {
sufMin[i] = Math.min(sufMin[i + 1], intervals[i][0]);
}
let ans = 0;
for (let i = 0; i < n; i++) {
// 左侧是否冲突
let leftOverlap = false;
// 右侧是否冲突
let rightOverlap = false;
if (i > 0 && preMax[i - 1] >= intervals[i][0]) {
leftOverlap = true;
}
if (i + 1 < n && sufMin[i + 1] <= intervals[i][1]) {
rightOverlap = true;
}
if (!leftOverlap && !rightOverlap) {
ans++;
}
}
return ans;
}
Go
go
package main
import (
"bufio"
"fmt"
"os"
"sort"
)
func getIsolationInterval(intervals [][]int) int {
// 按左端点升序排序,左端点相同按右端点升序排序
sort.Slice(intervals, func(i, j int) bool {
if intervals[i][0] != intervals[j][0] {
return intervals[i][0] < intervals[j][0]
}
return intervals[i][1] < intervals[j][1]
})
n := len(intervals)
// preMax[i]右端点能取的最大值
preMax := make([]int, n)
preMax[0] = intervals[0][1]
for i := 1; i < n; i++ {
if preMax[i-1] > intervals[i][1] {
preMax[i] = preMax[i-1]
} else {
preMax[i] = intervals[i][1]
}
}
// sufMin[i]左端点能取的最小值
sufMin := make([]int, n)
sufMin[n-1] = intervals[n-1][0]
for i := n - 2; i >= 0; i-- {
if sufMin[i+1] < intervals[i][0] {
sufMin[i] = sufMin[i+1]
} else {
sufMin[i] = intervals[i][0]
}
}
ans := 0
for i := 0; i < n; i++ {
// 左侧是否冲突
leftOverlap := false
// 右侧是否冲突
rightOverlap := false
if i > 0 && preMax[i-1] >= intervals[i][0] {
leftOverlap = true
}
if i+1 < n && sufMin[i+1] <= intervals[i][1] {
rightOverlap = true
}
if !leftOverlap && !rightOverlap {
ans++
}
}
return ans
}
func main() {
scanner := bufio.NewScanner(os.Stdin)
var intervals [][]int
for scanner.Scan() {
var l, r int
line := scanner.Text()
if line == "" {
break
}
fmt.Sscanf(line, "%d %d", &l, &r)
intervals = append(intervals, []int{l, r})
}
fmt.Println(getIsolationInterval(intervals))
}
C语言
cpp
#include <stdio.h>
#include <stdlib.h>
int cmp(const void *a, const void *b) {
int *x = (int *)a;
int *y = (int *)b;
if (x[0] != y[0]) {
return x[0] - y[0];
}
return x[1] - y[1];
}
int getIsolationInterval(int intervals[][2], int n) {
// 按左端点升序排序,左端点相同按右端点升序排序
qsort(intervals, n, sizeof(intervals[0]), cmp);
// preMax[i]右端点能取的最大值
int preMax[n];
preMax[0] = intervals[0][1];
for (int i = 1; i < n; i++) {
preMax[i] = preMax[i - 1] > intervals[i][1] ? preMax[i - 1] : intervals[i][1];
}
// sufMin[i]左端点能取的最小值
int sufMin[n];
sufMin[n - 1] = intervals[n - 1][0];
for (int i = n - 2; i >= 0; i--) {
sufMin[i] = sufMin[i + 1] < intervals[i][0] ? sufMin[i + 1] : intervals[i][0];
}
int ans = 0;
for (int i = 0; i < n; i++) {
// 左侧是否冲突
int leftOverlap = 0;
// 右侧是否冲突
int rightOverlap = 0;
if (i > 0 && preMax[i - 1] >= intervals[i][0]) {
leftOverlap = 1;
}
if (i + 1 < n && sufMin[i + 1] <= intervals[i][1]) {
rightOverlap = 1;
}
if (!leftOverlap && !rightOverlap) {
ans++;
}
}
return ans;
}
int main() {
int intervals[10000][2];
int n = 0;
// 每行输入一个区间:start end
while (scanf("%d %d", &intervals[n][0], &intervals[n][1]) == 2) {
n++;
}
printf("%d\n", getIsolationInterval(intervals, n));
return 0;
}