最近在做今日头条的笔试题碰到了区间合并问题
所以趁机把类似的问题总结一下
LeetCode 56
给出一个区间的集合,请合并所有重叠的区间。
示例 1:
输入: [[1,3],[2,6],[8,10],[15,18]] 输出: [[1,6],[8,10],[15,18]] 解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
输入: [[1,4],[4,5]] 输出: [[1,5]] 解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。
分析:合并区间关键在于寻找是否存在前一个区间的结束值大于后一个区间的开始值,若存在,则这两个区间就可以合并。理解这个并不难,但对数据的处理有一个小技巧,就是将所有区间的开始值和结束值都排好序,这样在合并区间的时候会更简单一些,这也是区间问题常用的套路(呵呵,没错就是套路),排序过后就是合并过程了,具体过程看代码吧。
/**
* Definition for an interval.
* public class Interval {
* int start;
* int end;
* Interval() { start = 0; end = 0; }
* Interval(int s, int e) { start = s; end = e; }
* }
*/
class Solution {
public List<Interval> merge(List<Interval> intervals) {
int n=intervals.size();
int[] starts=new int[n];
int[] ends=new int[n];
for(int i=0;i<n;i++){
starts[i]=intervals.get(i).start;
ends[i]=intervals.get(i).end;
}
Arrays.sort(starts);
Arrays.sort(ends);
List<Interval> res=new ArrayList<Interval>();
for(int i=0,j=0;i<n;i++){
if(i==n-1||starts[i+1]>ends[i]){
res.add(new Interval(starts[j],ends[i]));
j=i+1;
}
}
return res;
}
}
二:插入区间
57. Insert Interval
给出一个无重叠的 ,按照区间起始端点排序的区间列表。
在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。
示例 1:
输入: intervals = [[1,3],[6,9]], newInterval = [2,5] 输出: [[1,5],[6,9]]
示例 2:
输入: intervals =[[1,2],[3,5],[6,7],[8,10],[12,16]]
, newInterval =[4,8]
输出: [[1,2],[3,10],[12,16]] 解释: 这是因为新的区间[4,8]
与[3,5],[6,7],[8,10]
重叠。
/**
* Definition for an interval.
* public class Interval {
* int start;
* int end;
* Interval() { start = 0; end = 0; }
* Interval(int s, int e) { start = s; end = e; }
* }
*/
public class Solution {
//ArrayList<Interval> list=new ArrayList<>();
public List<Interval> insert(List<Interval> intervals, Interval newInterval) {
int[] starts=new int[intervals.size()+1];
int[] ends=new int[intervals.size()+1];
for(int i=0;i<intervals.size();i++) {
starts[i]=intervals.get(i).start;
ends[i]=intervals.get(i).end;
}
starts[intervals.size()]=newInterval.start;
ends[intervals.size()]=newInterval.end;
Arrays.sort(starts);
Arrays.sort(ends);
intervals.clear();
for(int i=0,j=0;i<starts.length;i++)
{
if(i==starts.length-1||starts[i+1]>ends[i])
{
intervals.add(new Interval(starts[j], ends[i]));
j=i+1;
}
}
return intervals;
}
}
三.
495. Teemo Attacking
在《英雄联盟》的世界中,有一个叫“提莫”的英雄,他的攻击可以让敌方英雄艾希(编者注:寒冰射手)进入中毒状态。现在,给出提莫对艾希的攻击时间序列和提莫攻击的中毒持续时间,你需要输出艾希的中毒状态总时长。
你可以认为提莫在给定的时间点进行攻击,并立即使艾希处于中毒状态。
示例1:
输入: [1,4], 2 输出: 4 原因: 在第1秒开始时,提莫开始对艾希进行攻击并使其立即中毒。中毒状态会维持2秒钟,直到第2秒钟结束。 在第4秒开始时,提莫再次攻击艾希,使得艾希获得另外2秒的中毒时间。 所以最终输出4秒。
示例2:
输入: [1,2], 2 输出: 3 原因: 在第1秒开始时,提莫开始对艾希进行攻击并使其立即中毒。中毒状态会维持2秒钟,直到第2秒钟结束。 但是在第2秒开始时,提莫再次攻击了已经处于中毒状态的艾希。 由于中毒状态不可叠加,提莫在第2秒开始时的这次攻击会在第3秒钟结束。 所以最终输出3。
注意:
- 你可以假定时间序列数组的总长度不超过10000。
- 你可以假定提莫攻击时间序列中的数字和提莫攻击的中毒持续时间都是非负整数,并且不超过10,000,000。
class Solution {
ArrayList<Interval> list=new ArrayList<>();
public int findPoisonedDuration(int[] timeSeries, int duration) {
int res=0;
int[] ends=new int[timeSeries.length];
for(int i=0;i<timeSeries.length;i++)
{
ends[i]=timeSeries[i]+duration;
}
Arrays.sort(timeSeries);
Arrays.sort(ends);
for(int i=0,j=0;i<timeSeries.length;i++)
{
if(i==timeSeries.length-1||timeSeries[i+1]>ends[i])
{
list.add(new Interval(timeSeries[j], ends[i]));
j=i+1;
}
}
for(int i=0;i<list.size();i++)
{
res=res+list.get(i).end-list.get(i).start;
}
return res;
}
}