在一个数轴上给出n
个线段,问选择不超过k
个线段,使得这k
个线段覆盖的数最多。
样例
样例1
输入:
[(1,2),(2,3),(3,4)]
2
输出: 4
说明:
选择线段(1,2),(3,4)可以覆盖1,2,3,4这个4个数。
样例2
输入:
[(1,2),(2,3),(1,7)]
2
输出: 7
说明:
选择线段(1,7)可以覆盖1,2,3,4,5,6,7这个7个数。
注意事项
0 <= k <= n
1 <= n <= 2000
- 线段的左右端点大于
0
,不超过2000
。
思路:感觉是难题。dp比较难构造,dp[i][j] 表示前i个数,最多用j个线段覆盖。找到第一个区间,i在这区间中,或者在区间左。这里有贪心思想。如在区间左。dp[i][j]=dp[i-1][j],否则dp[i][j]可能等于dp[start-1][j-1]+i-start+1(可能取这条线段)。所以要按起始位置排序区间。
/**
* Definition of Interval:
* public classs Interval {
* int start, end;
* Interval(int start, int end) {
* this.start = start;
* this.end = end;
* }
* }
*/
public class Solution {
/**
* @param intervals: The intervals
* @param k: The k
* @return: The answer
*/
public int maximumLineCoverage(List<Interval> intervals, int k) {
int[][] dp=new int[2003][k+1];
Collections.sort(intervals,new Comparator<Interval>(){
public int compare(Interval a,Interval b){
if(a.start==b.start){
return b.end-a.end;
}
return a.start-b.start;
}
});
int index=0;
int size=intervals.size();
for(int i=1;i<2003;i++){//取刚刚超过的那个点,有贪心思想
//找到第一个区间,i在这区间中,或者在区间左
while(index<size&&intervals.get(index).end<i){
index++;
}
for(int j=1;j<=k;j++){
dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
if(index<size&&intervals.get(index).start<=i){
int start=intervals.get(index).start;
dp[i][j]=Math.max(dp[start-1][j-1]+i-start+1,dp[i][j]);
}
}
}
return dp[2000][k];
}
}