435. 无重叠区间
思路:按照左边界从小到大进行排序,定义currRight记录当前覆盖范围的右边界,从第1个元素开始遍历数组,如果当前元素发生重叠,就让删除的值加一,并且更新覆盖范围的最小右边界(这里要表示要删除右边界更大的元素),否则只更新覆盖范围的右边界。
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
int count = 0;
// 按照起始位置从小到大进行排序
Arrays.sort(intervals, (a, b) -> {
return Integer.compare(a[0], b[0]);
});
// 当前覆盖范围的最小右边界
int minRight = intervals[0][1];
for (int i = 1; i < intervals.length; i++) {
if (intervals[i][0] < minRight) {
count++;
minRight = Math.min(minRight, intervals[i][1]);
} else {
minRight = intervals[i][1];
}
}
return count;
}
}
本题也可以按照右边界来从小到大排序,但同时也要注意:删除的是右边界较大的那个元素。
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
Arrays.sort(intervals, (a, b) -> {
// 按照区间右边界升序排序
return a[1] - b[1];
});
int count = 0;
int edge = Integer.MIN_VALUE;
for (int i = 0; i < intervals.length; i++) {
// 若上一个区间的右边界小于当前区间的左边界,说明无交集
if (edge <= intervals[i][0]) {
edge = intervals[i][1];
} else {
count++;
}
}
return count;
}
}
763.划分字母区间
思路:如果我们能够找到之前遍历过的所有字母的最远边界,那么这个边界就是要划分的地方。首先我们要记录每一个字母最后出现的位置,遍历字符串,不断更新出现过的字母的最远边界,如果当前下标和出现过的字母的最远边界相同,则该处为分割点。
class Solution {
public List<Integer> partitionLabels(String s) {
int[] hash = new int[26];
List<Integer> res = new ArrayList<>();
char[] ch = s.toCharArray();
// 记录每一个字母最后出现的位置。
for (int i = 0; i < ch.length; i++) {
hash[ch[i] - 'a'] = i;
}
int index = 0; // 当前片段出现过的字母的最远边界
int last = -1; // 上一个片段结束的下标
for (int i = 0; i < ch.length; i++) {
// 更新最远边界
index = Math.max(index, hash[ch[i] - 'a']);
if (index == i) {
res.add(i - last);
last = i;
}
}
return res;
}
}
56. 合并区间
思路:按照左边界从小到大排序,定义range记录需要合并的左边界和右边界,定义maxRight记录当前覆盖的最大右边界,如果发生重叠,更新最大右边界,否则收集结果并重置range和最大右边界。
class Solution {
public int[][] merge(int[][] intervals) {
List<int[]> res = new ArrayList<>();
// 按照左边界从小到大排序,左边界相同时右边界小的在前
Arrays.sort(intervals, (a, b) -> {
if (a[0] == b[0]) return Integer.compare(a[1], b[1]);
return Integer.compare(a[0], b[0]);
});
// 当前覆盖范围的最大右边界
int maxRight = intervals[0][1];
// 记录合并的范围
int[] range = new int[2];
range[0] = intervals[0][0];
for (int i = 1; i < intervals.length; i++) {
if (intervals[i][0] <= maxRight) { // 如果发生重叠,更新覆盖范围的最大右边界
maxRight = Math.max(intervals[i][1], minLeft);
} else { // 没有重叠,记录结果
range[1] = maxRight;
int[] t = {range[0], range[1]};
res.add(t);
// 重置记录数组和最大右边界
range[0] = intervals[i][0];
maxRight = intervals[i][1];
}
}
// 收集最后一个结果
range[1] = maxRight;
res.add(range);
return res.toArray(new int[res.size()][]);
}
}