区间分组
- 问题背景
给定 N 个闭区间 [ai,bi],请你将这些区间分成若干组,使得每组内部的区间两两之间(包括端点)没有交集,并使得组数尽可能小。
输出最小组数。
-
策略
- 将每个区间按左端点从小到大排序
- 从前往后枚举每个区间
- 枚举每个组
- 如果当前组的右端点小于当前区间的左端点,将其放进去,更新组的右端点为当前区间的右端点
- 如果每个组的右端点都大于当前区间的左端点,开个新的组,更新组的右端点为当前区间的右端点
- 枚举每个组
-
优化方案
- 每次枚举每个组的时候找的是所有组右端点的最小值
- 因此可以用小根堆来维护每个组的右端点
练习
03 区间分组
- 题目
- 题解1
//朴素版
import java.io.*;
import java.util.*;
public class Main {
public static final int N = 100010;
public static int n;
public static Pair[] range = new Pair[N];
//存每个组的右端点
public static int[] q = new int[N];
//有多少个组
public static int res = 0;
public static class Pair implements Comparable<Pair> {
public int first;
public int second;
public Pair(int first, int second) {
this.first = first;
this.second = second;
}
@Override
public int compareTo(Pair o) {
return this.first - o.first;
}
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
n = Integer.parseInt(br.readLine());
for (int i = 0; i < n; i++) {
String[] str1 = br.readLine().split(" ");
range[i] = new Pair(Integer.parseInt(str1[0]), Integer.parseInt(str1[1]));
}
//按照左端点排序
Arrays.sort(range, 0, n);
//初始化
Arrays.fill(q, -(int) 2e9);
//遍历每一个区间
for (int i = 0; i < n; i++) {
//flag表示这个区间是否加入到了一个组中
boolean flag = false;
//首先遍历目前所有的组 判断当前区间是否能加入到现有的组中
for (int j = 0; j < res; j++) {
//如果当前组的右端点 小于 当前区间的左端点
if (range[i].first > q[j]) {
//将当前区间加入到组中 将组的右端点更新成当前区间的右端点
q[j] = range[i].second;
flag = true;
break;
}
}
//如果当前区间无法加入到现有的组中 新开一个组 将组的右端点更新成当前区间的右端点
if (!flag) {
q[res++] = range[i].second;
}
}
pw.println(res);
pw.close();
br.close();
}
}
- 题解2
//堆优化版
import java.io.*;
import java.util.*;
public class Main {
public static final int N = 100010;
public static int n;
public static Pair[] range = new Pair[N];
//小根堆存储所有组中的右端点
public static PriorityQueue<Integer> queue = new PriorityQueue<>();
public static class Pair implements Comparable<Pair> {
public int first;
public int second;
public Pair(int first, int second) {
this.first = first;
this.second = second;
}
@Override
public int compareTo(Pair o) {
return this.first - o.first;
}
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
n = Integer.parseInt(br.readLine());
for (int i = 0; i < n; i++) {
String[] str1 = br.readLine().split(" ");
range[i] = new Pair(Integer.parseInt(str1[0]), Integer.parseInt(str1[1]));
}
//按照左端点排序
Arrays.sort(range, 0, n);
//初始化
queue.offer(-(int) 2e9);
for (int i = 0; i < n; i++) {
//获取堆顶元素 即所有组中右端点的最小值
int top = queue.peek();
//如果所有组中右端点的最小值 小于 当前区间的左端点 说明该区间可以加入到已有的组中
if (top < range[i].first) {
//更新
queue.poll();
queue.offer(range[i].second);
} else {
//所有组中右端点的最小值 小于 当前区间的左端点 说明该区间无法加入到已有的组中
//开一个新的组
queue.offer(range[i].second);
}
}
//堆的size就是组数
pw.println(queue.size());
pw.close();
br.close();
}
}