今天的三道题目,都算是 重叠区间 问题,大家可以好好感受一下。 都属于那种看起来好复杂,但一看贪心解法,惊呼:这么巧妙!还是属于那种,做过了也就会了,没做过就很难想出来。
不过大家把如下三题做了之后, 重叠区间 基本上差不多了
435. 无重叠区间
题目讲解:代码随想录
重点:
左边界排序我们就是直接求 重叠的区间,count为记录重叠区间数。
贪心算法:
局部最优: 把最长的移除。全局最优:移除了最少数量的重叠区间。
思路:
1. 按左边界排序
Arrays.sort(intervals, Comparator.comparingInt(a -> a[0]));
2. 遍历区间数组,发生了重叠就result++,更新最小右边界
int result = 0; for (int i = 1; i < intervals.length; i++) { // 当前区间与上一个区间发生了重叠 if (intervals[i][0] < intervals[i - 1][1]) { result++; // 把当前区间右边界更新为最小右边界 intervals[i][1] = Math.min(intervals[i][1], intervals[i - 1][1]); } }
public int eraseOverlapIntervals(int[][] intervals) {
// 没必要给右边界排序,因为重叠的时候会按照最小的右边界取
Arrays.sort(intervals, Comparator.comparingInt(a -> a[0]));
int result = 0;
for (int i = 1; i < intervals.length; i++) {
// 当前区间与上一个区间发生了重叠
if (intervals[i][0] < intervals[i - 1][1]) {
result++;
// 把当前区间右边界更新为最小右边界
intervals[i][1] = Math.min(intervals[i][1], intervals[i - 1][1]);
}
}
return result;
}
763. 划分字母区间
题目讲解: 代码随想录
重点:
1. 在遍历的过程中相当于是要找每一个字母的边界,如果找到之前遍历过的所有字母的最远边界,说明这个边界就是分割点了。此时前面出现过所有字母,最远也就到这个边界了。
可以分为如下两步:
- 统计每一个字符最后出现的位置
- 从头遍历字符,并更新字符的最远出现下标,如果找到字符最远出现位置下标和当前下标相等了,则找到了分割点
思路:
1. 记录每个字母的最远下标
int[] lastIndex = new int[27]; for (int i = 0; i < s.length(); i++) { lastIndex[s.charAt(i) - 'a'] = i; }
2. 遍历,寻找当前区间的起始和终止下标
for (int i = 0; i < s.length(); i++) { // 寻找当前区间的最大的最远下标 endIndex = Math.max(endIndex, lastIndex[s.charAt(i) - 'a']); // 到当前区间末尾 if (i == endIndex) { result.add(endIndex - startIndex + 1); startIndex = endIndex + 1; } }
public List<Integer> partitionLabels(String s) {
// 记录每个字母的最远下标
int[] lastIndex = new int[27];
for (int i = 0; i < s.length(); i++) {
lastIndex[s.charAt(i) - 'a'] = i;
}
ArrayList<Integer> result = new ArrayList<>();
// 记录当前区间的起始和终止下标
int startIndex = 0, endIndex = 0;
for (int i = 0; i < s.length(); i++) {
// 寻找当前区间的最大的最远下标
endIndex = Math.max(endIndex, lastIndex[s.charAt(i) - 'a']);
// 到当前区间末尾
if (i == endIndex) {
result.add(endIndex - startIndex + 1);
startIndex = endIndex + 1;
}
}
return result;
}
56. 合并区间
本题相对来说就比较难了。
题目讲解:代码随想录
重点:
思路:
~