435. 无重叠区间
完成
思路:
本题的贪心策略是,把区间按左端从小到大排序,当碰到重叠区间时,优先去掉右端更大的,减少后续重叠的可能。也可以理解为优先保留跨度更小的区间,跨度小的区间和其他区间重叠的可能性就小。
代码
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
int res = 0;
Arrays.sort(intervals, (a,b)->a[0]==b[0]?a[1]-b[1]:a[0]-b[0]);
int end = intervals[0][1];
for (int i = 1; i < intervals.length; i++) {
if(intervals[i][0]<end){ // 重叠
res++;
// 这里取二者之小 就是保留右端更小的区间,即跨度小的区间
end = Math.min(end, intervals[i][1]);
}else end = intervals[i][1];
}
return res;
}
}
763.划分字母区间
完成
思路:
遍历的过程中相当于是要找每一个字母的边界,如果找到之前遍历过的所有字母的最远边界,说明这个边界就是分割点。
代码
class Solution {
public List<Integer> partitionLabels(String s) {
List<Integer> res = new ArrayList<>();
// 统计每个字符出现的最远位置
int[] nums = new int[26];
for (int i = 0; i < s.length(); i++) {
nums[s.charAt(i)-'a'] = i;
}
int left = 0;
int right = 0;
// 遍历字符串,更新每组的最远位置
for (int i = 0; i < s.length(); i++) {
right = Math.max(right, nums[s.charAt(i)-'a']);
if(i==right){ // 做分割
res.add(right-left+1);
left = i+1;
}
}
return res;
}
}
56. 合并区间
完成
代码
重叠区间问题,思路是一样的
class Solution {
public int[][] merge(int[][] intervals) {
List<int[]> res = new ArrayList<>();
Arrays.sort(intervals,(a,b)->a[0]-b[0]);
res.add(intervals[0]);
for (int i = 1; i < intervals.length; i++) {
// 重叠
if(intervals[i][0]<=res.getLast()[1]){
// 构造新的区间范围
int start = res.getLast()[0];
int end = Math.max(intervals[i][1], res.getLast()[1]);
res.removeLast();
res.add(new int[]{start,end});
}
else{
res.add(intervals[i]);
}
}
return res.toArray(new int[res.size()][]);
}
}
下面的代码在合并区间时不涉及出队入队,稍快一些
class Solution {
public int[][] merge(int[][] intervals) {
List<int[]> res = new ArrayList<>();
Arrays.sort(intervals,(a,b)->a[0]-b[0]);
int left = intervals[0][0];
int right = intervals[0][1];
for (int i = 1; i < intervals.length; i++) {
if(intervals[i][0]<=right){
right = Math.max(right, intervals[i][1]);
}else{
res.add(new int[]{left,right});
left = intervals[i][0];
right = intervals[i][1];
}
}
// 需要额外添加最后一个区间
res.add(new int[]{left,right});
return res.toArray(new int[res.size()][]);
}
}