区间插入并合并(InsertInterval)

    /*
     * 区间合并
     * 在一个有序不重合和区间组中插入一个新区间,确保新的区间组有序且不重合
     * 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;
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值