MyCalendar I,II 问题

1.MyCalendar I

    /*
    //实现我的日历类,类里面有一个 Book(int start,int end)方法
    //代表要添加一个代办事件,事件的时间区间,这个区间是半开区间[start,end),即左闭右开
    //每次添加一个事件后,如果时间区间和已有的区间没有冲突则返回true,否则返回false
    //eg:
    *    MyCalendar.book(10, 20); // returns true
         MyCalendar.book(15, 25); // returns false
         MyCalendar.book(20, 30); // returns true
    */

    List<Interval> events = new List<Interval>();
    private bool Book(int start, int end)
    {
        Interval interval = new Interval(start, end);
        for (int i = 0; i < events.Count; i++)
        {
            if (interval.y <= events[i].x)
            {
                events.Insert(i, interval);               //新添加的事件结束时间小于事件[i]的开始时间,可以添加成功
                                                          //将新事件添加到当前位置,使列表事件有序
                return true;
            }
            if (interval.x < events[i].y)                 //新添加事件的时间节点有冲突
            {                                             //直接返回false
                return false;
            }
        }
        events.Add(interval);                             //遍历完,时间没有冲突,事件也没有添加
        return true;                                      //说明这个事件在所有事件后面
    }

定义区间的结构体

public 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);
    }
}

2.MyCalendar II

    /*
     * 升级版,同一时间可以添加两个事件,多于两个返回false
     * MyCalendar.book(10, 20); // returns true
     * MyCalendar.book(50, 60); // returns true
     * MyCalendar.book(10, 40); // returns true
     * MyCalendar.book(5, 15); // returns false
     * MyCalendar.book(5, 10); // returns true
     * MyCalendar.book(25, 55); // returns true
     * 
     * 思路
     * 1.用两个list保存事件,list1保存已经成功添加(包括没有区间重叠的喝有一次区间重叠的)的区间,list2保存有两层重叠的区间间隔
     * 2.每次先在list2中查看是否有重叠区间,如果有直接返回false,若无则在list1中查看是否有重叠
     * 3.若与list1有重叠,则把重叠部分的区间加入list2中,因为已经验证过与list2没有重叠所以直接添加list1并返回true
     */

    List<Interval> list1 = new List<Interval>();
    List<Interval> list2 = new List<Interval>();
    private bool BookII(int start, int end)
    {
        Interval interval = new Interval(start, end);
        foreach (var item in list2)
        {
            if (!(interval.x >= item.y || interval.y <= item.x))
                return false;
        }
        for (int i = 0; i < list1.Count; i++)
        {
            if (interval.x >= list1[i].y || interval.y <= list1[i].x)
                continue;
            Interval temp = new Interval(Mathf.Max(interval.x, list1[i].x), Mathf.Min(interval.y, list1[i].y));
            list2.Add(temp);
        }
        list1.Add(interval);
        return true;
    }

下面是一个巧妙的方法先看代码

    Dictionary<int, int> map = new Dictionary<int, int>();
    private bool BookII2(int start, int end)
    {
        if (map.ContainsKey(start))
            map[start]++;
        else
            map.Add(start, 1);
        if (map.ContainsKey(end))
            map[end]--;
        else
            map.Add(end, -1);
        //将时间节点按升序排序
        map = map.OrderBy(o => o.Key).ToDictionary(k => k.Key, v => v.Value);
        int count = 0;
        foreach (var item in map)
        {
            count += item.Value;
            if (count == 3)
            {
                //还原此次添加的值,返回false
                map[start]--;
                map[end]++;
                return false;
            }
        }
        return true;
    }

     * 思路:利用dictionary来存储各个时间节点出现次数(时间节点做Key,出现次数做Value),
     *            如果是开始时间节点就把值+1,结束值节点就把值-1,然后遍历map,计算各个节点出现次数和,
     *            如果次数和大于等于3(事实上等于的时候已经返回不可能大于)说明添加的事件重叠次数超过三次,返回false,并将                      此次的start和end值还原
     * 比如:当添加(10,20)时,将10,20添加到map
     *       10 --> 1    
     *       20 --> -1      遍历时count最大为1<3 return true;
     *      添加(50,60)时:
     *       10 --> 1  
     *       20 --> -1
     *       50 --> 1   
     *       60 --> -1       遍历时count最大为1<3 return true;
     *      添加(10,40)时
     *       10 --> 2  
     *       20 --> -1
     *       40 --> -1
     *       50 --> 1   
     *       60 --> -1       遍历时count最大为2<3 return true;
     *      添加(5,15)时
     *       5  --> 1
     *       10 --> 2  
     *       15 --> -1
     *       20 --> -1
     *       40 --> -1
     *       50 --> 1   
     *       60 --> -1       遍历时count最大为3 return false; 并将刚添加的值还原:5-->0,15-->0
     *      添加(5,10)时
     *       5  --> 1
     *       10 --> 1  
     *       15 --> 0
     *       20 --> -1
     *       40 --> -1
     *       50 --> 1   
     *       60 --> -1       遍历时count最大为2 return true; 
     */

利用这个方法可以可以解决这个系列问题,不管时可以有一次时间区间重合,2次时间区间重合,还是n次时间区间重合,只需改变count 的判断值即可

区间有关题目:

        区间合并(IntervalMerging)

        区间插入并合并(InsertInterval)

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值