老师Java动态规划解法貌似超时了
来源:10-2 贪心算法与动态规划的关系 Non-overlapping Intervals
湿地车手
2021-10-24
还有老师,为什么按照起始位置排序以后就能动态规划求出最长子序列了呢?隐隐约约好像是这样的,但是老是想不清楚。
class Solution {
public static class Interval {
int start;
int end;
Interval() { start = 0; end = 0; }
Interval(int s, int e) { start = s; end = e; }
}
// 相当于求最长上升子序列,再剪一剪
public int eraseOverlapIntervals(int[][] intervals) {
if(intervals.length == 1) return 0;
Interval[] ranges = new Interval[intervals.length];
int totalLen = intervals.length;
for(int i = 0; i < totalLen; i++) {
ranges[i] = new Interval(intervals[i][0], intervals[i][1]);
}
Arrays.sort(ranges, new Comparator<Interval>() {
@Override
public int compare(Interval o1, Interval o2) {
if(o1.start != o2.start)
return o1.start - o2.start;
return o1.end - o2.end;
}
});
int[] memo = new int[intervals.length];
Arrays.fill(memo, -1);
int max = 1;
for(int i = 0; i < totalLen; i++) {
max = Math.max(max, tryFindMax(i, ranges, memo));
}
return totalLen - max;
}
// 寻找从 index 开始(必选)的最长上升子序列
private int tryFindMax(int index, Interval[] intervals, int[] memo) {
if(index >= intervals.length) return 0;
if(memo[index] != -1) return memo[index];
int max = 1;
for(int next = index + 1; next < intervals.length; next++) {
int curR = intervals[index].end;
int nextL = intervals[next].start;
if(nextL < curR) {
continue;
} else {
max = Math.max(max, 1 + tryFindMax(next, intervals, memo));
}
}
return memo[index] = max;
}
}
跟老师思路一样,就是换成了递归写法,迭代写法一样超时试了一下
写回答
1回答
-
liuyubobobo
2021-10-25
这是第几号问题?
==========
这个问题新加了测试用例,O(n^2) 的动态规划已经过不了了。需要使用 O(nlogn) 的贪心算法。方法是:首先,把每个线段按照结束时间排序。先取结束时间最早的,再取剩下的时间段里结束时间最早的,依次类推。我的参考代码:https://github.com/liuyubobobo/Play-Leetcode/blob/master/0001-0500/0435-Non-overlapping-Intervals/cpp-0435/main4.cpp
可以思考一下为什么用结束时间排序,可以这样贪心得到解?提示:反证法。
==========
为什么动态规划按照起始时间排序也可以得到解?首先不排序肯定不行。反例随便举:[3, 4] [1, 2]
在排好序以后,我们保证了后一个时间段的起始时间肯定晚于前一个时间段。而在这重循环中:for(int next = index + 1; next < intervals.length; next++)
我们相当于枚举了每一个时间段是否取用。排序保证了不会漏,枚举的过程寻找了最优解。
继续加油!:)
042021-10-30
相似问题