/*
* 区间合并
* 在一个有序不重合和区间组中插入一个新区间,确保新的区间组有序且不重合
* eg;
* Insert (2, 5) into [(1,2), (5,9)], we get [(1,9)].
* Insert (3, 4) into [(1,2), (5,9)], we get [(1,2), (3,4), (5,9)].
*/
看到这个题目就想到之前做的无序区间合并的题目,可以按照无序区间合并的思路来做
代码如下
//定义区间的结构体
private struct Interval
{
public int x;
public int y;
public Interval(int x, int y)
{
this.x = x;
this.y = y;
}
public override string ToString()
{
return string.Format("({0},{1})", x, y);
}
}
private List<Interval> InsertInterval(Interval interval, List<Interval> list)
{
if (list.Count == 0 || list[list.Count - 1].y < interval.x)
{
list.Add(interval);
return list;
}
int insertIndex = 0; //存放interval插入的位置,减少合并区间是不必要的循环
for (int i = 0; i <= list.Count; i++)
{
if (i == list.Count || interval.x < list[i].x)
{
list.Insert(i, interval);
insertIndex = i;
break;
}
}
int count = 0; //存放自加次数,
for (int i = insertIndex - 1; i < list.Count - 1;) //从插入的前一个数开始合并
{
if (i < 0)
i = 0;
if (list[i].y < list[i + 1].x)
{
i++;
count++;
if (count >= 2) //因为之前的列表区间都是有序不重合的,所以只需要将插入的哪个区间和合并进来就可以了,减少不必要循环
break; //为什么 >=2 呢,因为正常情况下累加一次就说明新插入区间已经合并到列表了,但事实我们是从插入
//区间的前一个区间开始合并的,有可能前一个区间不用和新插入的区间进行合并,这时候会走if语句
//count会自加一次,设置count>=2 跳出循环可以避免这种情况下,新插入区间不会和后面区间合并的情况
}
else
{
list[i] = new Interval(list[i].x, Mathf.Max(list[i].y, list[i + 1].y));
list.RemoveAt(i + 1);
}
}
return list;
}
其实我们还可以将算法简化一下,我门重新定义一个list来存储返回的结果,以空间看来换取时间
解法二:
private List<Interval> InsertInterval2(List<Interval> list, Interval interval)
{
List<Interval> res = new List<Interval>();
int insertPos = 0;
foreach (Interval item in list)
{
if (item.y < interval.x)
{
res.Add(item);
insertPos++;
}
else if(interval.y<item.x)
{
//已找到要插入的位置,只需将item添加到res即可,insertPos不需自增
//说明要插入的区间和原来区间不存在交集,只需循环完插入就可以
res.Add(item);
}
else
{
interval.x = Mathf.Min(item.x, interval.x); //有交集,重新给拆入的区间赋值
interval.y = Mathf.Max(item.y, interval.y);
}
}
res.Insert(insertPos,interval);
return res;
}