问题描述
给出一段长度为n的区间和m条线段,每条线段有其起始点xi和终止点yi,现在我们想知道最少用几条线段就可以覆盖这一个区间。
输入格式
第一行包含两个整数n,m
接下来m行 每行两个数 xi yi 保证 xi<=yi
输出格式
输出1行,包含一个整数,表示最少线段数。如果无法覆盖 输出-1;
1、解题分析
思考一下,如果这里有两条线段, line1与line2,它们的x坐标相同,那么选择哪条线段覆盖呢?毫无疑问选择最长的那条,也就是y坐标最大的一条覆盖。本题采用贪心算法
- 将所有的线存储在二维数组 l i n e s [ n ] [ 2 ] lines[ n ][ 2] lines[n][2] 中,将数组排序,x坐标不同以x坐标升序排序,x坐标相拥就以y坐标降序排序,现在相同x坐标的线以y降序的方式连续存储在数组中。
- 根据贪心算法,相同x坐标的线保留y坐标最大的一条,其余相同x坐标的线删除掉。这里我仍将删除后的线存放在lines数组中,删除后的长度为 c u r N u m curNum curNum
- 使用 e n d end end记录当前覆盖的位置,循环中遍历所有x<=end的线段,获取能够覆盖的最远长度,为此循环相当于选取了一根线段,让结果值++,同时还要考虑是否能完全覆盖,也就是说一次循环后end的长度没有变化,说明无法覆盖,直接输出-1
类似的解法可以参考LeetCode的这道题55. 跳跃游戏
2、代码
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int len = cin.nextInt();
int n = cin.nextInt();
int [][]lines=new int[n][2];
for(int i=0;i<n;++i){
lines[i][0]=cin.nextInt();
lines[i][1]=cin.nextInt();
}
Arrays.sort(lines,((a,b)-> {
if(a[0]!=b[0]) {
return a[0]-b[0];
}
return b[1] - a[1];
}));
int ans=0;
int end=1;
int pre=Integer.MIN_VALUE;
int curNum=0;
//删除x相同的其余的线段
for(int i=0;i<n;++i){
int []line=lines[i];
if(line[0]==pre){
continue;
}
lines[curNum++]=line;
}
//开始循环
while(end<len){
int nextEnd=end;
for(int i=0;i<curNum;++i){
int []line=lines[i];
if(line[0]<=end){
nextEnd = Math.max(nextEnd, line[1]);
}
}
++ans;
if(end==nextEnd){
break;
}
end=nextEnd;
}
System.out.println(end >= len ? ans : -1);
}
}