①、无重叠区间
给定一个区间的集合
intervals
,其中intervals[i] = [starti, endi]
。返回 需要移除区间的最小数量,使剩余区间互不重叠 。
事例:
输入: intervals = [[1,2],[2,3],[3,4],[1,3]] 输出: 1 解释: 移除 [1,3] 后,剩下的区间没有重叠。
思路:
跟上一题的射箭类似,for循环遍历数组,统计下重复区间,然后返回重复区间即可。
具体做法:为了使重复区间尽量紧凑,首先将数组排序,根据左边界排序,此时 重复区间逻辑为: intervals[i][0] < pre,pre即为重复区间的右边界,每次重复时,取最小右边界。若开始新的区间统计,则要刷新pre的值。
代码:
public int eraseOverlapIntervals(int[][] intervals) {
if(intervals.length == 0) return 0;
Arrays.sort(intervals, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return Integer.compare(o1[0],o2[0]);
}
});
int count = 0;
int pre = intervals[0][1];
for(int i = 1;i < intervals.length;i++){
if(pre > intervals[i][0]){
count++;
pre = Math.min(pre,intervals[i][1]);
}else{
pre = intervals[i][1];
}
}
return count;
}
②、划分字母区间
给你一个字符串
s
。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是
s
。返回一个表示每个字符串片段的长度的列表。
事例:
输入:s = "ababcbacadefegdehijhklij" 输出:[9,7,8] 解释: 划分结果为 "ababcbaca"、"defegde"、"hijhklij" 。 每个字母最多出现在一个片段中。 像 "ababcbacadefegde", "hijhklij" 这样的划分是错误的,因为划分的片段数较少。
思路:
由于每个字母最多出现在一个片段,故需要一个数组或map映射字母最后出现的索引,得到每个字母的最后索引时,遍历字符串,用一个int变量记录最远索引farIndex,更新维护farIndex,当遍历到farIndex时,得到的片段长度为farIndex - startIndex + 1,记录然后更新startIndex = i + 1。
代码:
public List<Integer> partitionLabels(String s) {
// if(s == null || s.length() == 0) return new ArrayList<>();
// //存入映射
// Map<Character,Integer> map = new HashMap<>();
// for(int i = 0;i < s.length();i++){
// char c = s.charAt(i);
// map.put(c,i);
// }
// int farIndex = 0;
// int startIndex = 0;
// List<Integer> res = new ArrayList<>();
// for(int i = 0;i < s.length();i++){
// char c = s.charAt(i);
// int lastIndex = map.get(c);
// farIndex = Math.max(farIndex,lastIndex);
// if(farIndex == i){
// //恰好分成片段
// res.add(farIndex - startIndex + 1);
// startIndex = i + 1;
// }
// }
// return res;
//创建数组映射
if(s == null || s.length() == 0) return new ArrayList<>();
int[] help = new int[26];
for(int i = 0;i < s.length();i++){
help[s.charAt(i) - 'a'] = i;
}
int farIndex = 0;
int startIndex = 0;
List<Integer> res = new ArrayList<>();
for(int i = 0;i < s.length();i++){
int lastIndex = help[s.charAt(i) - 'a'];
farIndex = Math.max(farIndex,lastIndex);
if(i == farIndex){
//切割
res.add(farIndex - startIndex + 1);
startIndex = i + 1;
}
}
return res;
}
③、合并区间
以数组
intervals
表示若干个区间的集合,其中单个区间为intervals[i] = [starti, endi]
。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
事例:
输入:intervals = [[1,3],[2,6],[8,10],[15,18]] 输出:[[1,6],[8,10],[15,18]] 解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
思路:
跟射箭那题类似,也是先统计下重复区间,然后尽量用一个区间覆盖重复区间,即取重复区间里的并集作为新区间。最后统计无重复区间和新区间即可。
代码:
public int[][] merge(int[][] intervals) {
if(intervals == null || intervals.length == 0) return intervals;
Arrays.sort(intervals, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return Integer.compare(o1[0],o2[0]);
}
});
int left = intervals[0][0]; //记录各区间的左边界
int right = intervals[0][1]; //记录各区间的右边界
List<int[]> help = new ArrayList<>();
int count = 0;
for(int i = 1;i < intervals.length;i++){
if(right >= intervals[i][0]){
//重叠了 更新区间
left = Math.min(left,intervals[i][0]);
right = Math.max(right,intervals[i][1]);
}else{
//保存上个区间
help.add(new int[]{left,right});
left = intervals[i][0];
right = intervals[i][1];
count++;
}
}
help.add(new int[]{left,right});
count++;
int[][] res = new int[count][2];
for(int i = 0;i < count;i++){
res[i] = help.get(i);
}
return res;
}