435. 无重叠区间
题目链接:435. 无重叠区间
思路: 区间调度问题思路可以分为以下三步:
1、从区间集合 intvs 中选择一个区间 x,这个 x 是在当前所有区间中结束最早的(end 最小)。
2、把所有与 x 区间相交的区间从区间集合 intvs 中删除。
3、重复步骤 1 和 2,直到 intvs 为空为止。之前选出的那些 x 就是最大不相交子集
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
int n = intervals.length;
return n - intervalSchedule(intervals);
}
int intervalSchedule(int[][] intvs) {
Arrays.sort(intvs, (a, b) -> {
return a[1] - b[1];
});
int count = 1;
int end = intvs[0][1];
for (int[] intv : intvs) {
int start = intv[0];
if (start >= end) {
count++;
end = intv[1];
}
}
return count;
}
}
763. 划分字母区间
题目链接:763. 划分字母区间
思路: 在遍历的过程中相当于是要找每一个字母的边界,如果找到之前遍历过的所有字母的最远边界,说明这个边界就是分割点了。此时前面出现过所有字母,最远也就到这个边界了。
可以分为如下两步:
- 统计每一个字符最后出现的位置
- 从头遍历字符,并更新字符的最远出现下标,如果找到字符最远出现位置下标和当前下标相等了,则找到了分割点
class Solution {
public List<Integer> partitionLabels(String s) {
List<Integer> res = new LinkedList<>();
int[] edge = new int[26];
char[] ch = s.toCharArray();
for (int i = 0; i < s.length(); i++) {
edge[ch[i] - 'a'] = i;
}
int index = 0;
int last = -1;
for (int i = 0; i < s.length(); i++) {
index = Math.max(index, edge[ch[i] - 'a']);
if (i == index) {
res.add(i - last);
last = i;
}
}
return res;
}
}
6. 合并区间
题目链接:6. 合并区间
思路:
先按区间的 start 排序,对于几个相交区间合并后的结果区间 x,x.start 一定是这些相交区间中 start 最小的,x.end 一定是这些相交区间中 end 最大的。由于已经排了序,x.start 很好确定,求 x.end 也很容易,可以类比在数组中找最大值的过程。
class Solution {
public int[][] merge(int[][] intervals) {
LinkedList<int[]> res = new LinkedList<>();
Arrays.sort(intervals, (a, b) -> {
return a[0] - b[0];
});
res.add(intervals[0]);
for (int[] intv : intervals) {
int[] last = res.getLast();
if (intv[0] <= last[1]) {
last[1] = Math.max(intv[1], last[1]);
} else {
res.add(new int[]{intv[0], intv[1]});
}
}
return res.toArray(new int[0][0]);
}
}