【数组】我的日程安排表II-差分数组

题目描述

实现一个MyCalendar,要求添加的时间不能重复三次;给定类中有,构造函数:MyCalendar 和 book方法,其中book方法的入参是[start, end)。

示例1:

MyCalendar();
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

解决思路

方法一

可以使用暴力解法,提供2个List;其中一个存储冲突后的交集,另外一个存储实际传入的[start, end);

示例图如下:

加入[10, 20),没有冲突;

加入[50, 60),没有冲突;

加入[10, 40),有冲突, 求交集[10, 20),放入另外一个secondList中;

加入[5, 15),发现在secondList中有冲突,直接返回false;

加入[5, 10),没有冲突;

加入[25, 55),有冲突,求交集[25, 40),[50, 55)放入另外一个secondList中

 代码实现如下:

import java.util.ArrayList;
import java.util.List;

class MyCalendarTwo1 {

    List<int[]> firstList;
    List<int[]> secondList;

    public MyCalendarTwo1() {
        firstList = new ArrayList<>();
        secondList = new ArrayList<>();
    }

    public boolean book(int start, int end) {

        for (int[] second : secondList) {
            int s = second[0];
            int e = second[1];
            if (start >= s && end <= e) {
                return false;
            } else if (start <= s && end >= e) {
                return false;
            } else if (start >= s && start < e) {
                return false;
            } else if (end > s && end <= e) {
                return false;
            }
        }

        for (int[] first : firstList) {
            int s = first[0];
            int e = first[1];
            // 考虑哪些部分要写入到second
            if (start >= s && end <= e) {
                secondList.add(new int[]{start, end});
            } else if (start <= s && end >= e) {
                secondList.add(new int[]{s, e});
            } else if (start >= s && start < e) {
                secondList.add(new int[]{start, e});
            } else if (end > s && end <= e) {
                secondList.add(new int[]{s, end});
            }
        }
        firstList.add(new int[]{start, end});
        return true;
    }

    public static void main(String[] args) {
        MyCalendarTwo1 myCalendarTwo = new MyCalendarTwo1();
        System.out.println(myCalendarTwo.book(10, 20));
        System.out.println(myCalendarTwo.book(50, 60));
        System.out.println(myCalendarTwo.book(10, 40));
        System.out.println(myCalendarTwo.book(5, 15));
        System.out.println(myCalendarTwo.book(5, 10));
        System.out.println(myCalendarTwo.book(25, 55));
    }
}

方法二

使用差分数组,解决上述问题,即每次记录start和end的值,start加1,end减1;每次book操作时,遍历结果集,如果结果集大于2,则返回false。

示例图:

在执行[5,15) 时,计算结果为3,原因5计算1次,10计算2次,总共3次,最终需要把这个数据删除。

具体代码实现:


import java.util.Map;
import java.util.TreeMap;

class MyCalendarTwo {

    TreeMap<Integer, Integer> treeMap;

    public MyCalendarTwo() {
        treeMap = new TreeMap<>();
    }

    public boolean book(int start, int end) {

        treeMap.put(start, treeMap.getOrDefault(start, 0) + 1);
        treeMap.put(end, treeMap.getOrDefault(end, 0) - 1);

        int sum = 0;
        for (Map.Entry<Integer, Integer> entry : treeMap.entrySet()) {

            sum += entry.getValue();

            if (sum > 2) {
                treeMap.put(start, treeMap.getOrDefault(start, 0) - 1);
                treeMap.put(end, treeMap.getOrDefault(end, 0) + 1);
                return false;
            }
        }
        return true;

    }

    public static void main(String[] args) {
        MyCalendarTwo myCalendarTwo = new MyCalendarTwo();
        System.out.println(myCalendarTwo.book(10, 20));
        System.out.println(myCalendarTwo.book(50, 60));
        System.out.println(myCalendarTwo.book(10, 40));
        System.out.println(myCalendarTwo.book(5, 15));
        System.out.println(myCalendarTwo.book(5, 10));
        System.out.println(myCalendarTwo.book(25, 55));
    }
}

总结 

从代码实现角度,第二种方法明显简单很多,不必考虑复杂的计算;从实际测试结果来看时间复杂度要大于第一种方法的,我个人更喜欢第二种解法。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值