华为OD题目:最少数量线段覆盖
知识点排序贪心Q
时间限制: 1s 空间限制: 256MB 限定语言: 不限
题目描述:
给定坐标轴上的一组线段,线段的起点和终点均为整数并且长度不小于1,请你从中找到最少数量的线段,这些线段可以覆盖住所有线段。
输入描述:第一行输入为所有线段的数量,不超过10000,后面每行表示一条线段,格式为”x,y",x和y分别表示起点和终点,取值范围是[-105,1051]
输出描述:
最少线段数量,为正整数
示例1
输入:
3
1,4
2,5
3,6
输出:
2
4
1,4
2,5
3,6
10,20
输出:
3
4
1,4
2,5
3,6
1,10
输出:
3
说明:
选取2条线段[1,4]和[3,6]即可,这两条线段可以覆盖[2,5]
解题思路:
- 参考: https://blog.csdn.net/qq_34465338/article/details/128478461
public class My {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = Integer.parseInt(sc.nextLine());
List<int[]> list = new ArrayList<>();
for (int i = 0; i < n; i++) {
String line = sc.nextLine();
String[] strings = line.split(",");
int left = Integer.parseInt(strings[0]);
int right = Integer.parseInt(strings[1]);
int[] node = new int[]{left, right};
list.add(node);
}
//将每个线段,按照左侧升序排列,如果左侧相等,则按照右侧降序排列(这里千万不要搞错了)
list.sort((a1, a2) -> {
if (a1[0] != a2[0]) {
return a1[0] - a2[0];
}else {
return a2[1] - a1[1];
}
});
//下面是初始化
int total = 1;
int[] ints = list.get(0);
//已经覆盖的右节点
int coveredRight = ints[1];
//最大右节点
int maxRight = ints[1];
for (int i = 1; i < list.size(); i++) {
int[] node = list.get(i);
int left = node[0];
int right = node[1];
//如果当前线段左节点比前面的右节点小,说明此线段可以和前面的合并,
if (left <= coveredRight) {
//如果此线段的右节点比maxRight大,更新maxRight
maxRight = Math.max(maxRight, right);
}else {
//如果当前线段左节点比前面的右节点大,先将之前未合并的合并,合并次数+1,合并后 覆盖线段右节点coveredRight 设置为maxRight
if (maxRight > coveredRight) {
total++;
coveredRight = maxRight;
}
//接着比较当前左节点与覆盖后的右节点,如果左节点比覆盖后的小
if (left <= coveredRight) {
maxRight = Math.max(maxRight, right);
}else {
//如果当前线段左节点比前面的右节点大,合并次数+1,合并后,更新maxRight和coveredRight
total++;
maxRight = right;
coveredRight = right;
}
}
}
if (maxRight > coveredRight) {
total++;
}
System.out.println(total);
}
}