【问题标题】:Why the array need to be sorted first in "Meeting Rooms 2" of Leetcode?为什么在 Leetcode 的“会议室 2”中需要先对数组进行排序?
【发布时间】:2017-07-24 22:17:40
【问题描述】:

以下是 Leetcode 中“会议室 2”的问题:

给定一个由开始和结束组成的会议时间间隔数组 次 [[s1,e1],[s2,e2],...] (si

例如,给定 [[0, 30],[5, 10],[15, 20]],返回 2。

众所周知,一种可能的解决方案是在比较相邻会议的开始和结束时间之前对区间数组进行排序。

    public int minMeetingRooms(Interval[] intervals) {
        Arrays.sort(intervals, new Comparator<Interval>() {
            public int compare(Interval a, Interval b) {
                return a.start - b.start;
            }
        });
        List<Interval> list = new ArrayList<>(Arrays.asList(intervals));
        int count = 0;
        while (!list.isEmpty()) {
            int end = list.remove(0).end; count++; // create new timeline
            Iterator<Interval> ite = list.iterator();
            while (ite.hasNext()) {
                Interval next = ite.next();
                if (next.start >= end) { // add to current timeline
                    end = next.end;
                    ite.remove();
                }
            }
        }
        return count;
    }

但是假设我们有以下代码来检测两次会议之间的时间冲突,

    private boolean isConflict(Interval a, Interval b) {
        boolean abfb = (a.start < b.start && a.end <= b.start);
        boolean aaftb = (b.start < a.start && b.end <= a.start);
        return !(abfb || aaftb);
    }

例如,我们有间隔:[[15,20],[12,14],[1,17],[0,30],[7,10],[5,10]]。以[15,20] 开头, Room#1的时间表应该是:[[7,10],[12,14],[15,20]]

现在还是[[1,17],[0,30],[5,10]],他们都需要一个新房间, Room#2 : [[1,17]], Room#3 : [[0,30]], Room#4 : [[5,10]], 所以我们总共需要4 个房间。

这是代码,

    public int minMeetingRooms(Interval[] intervals) {
        List<Interval> list = new LinkedList<>(Arrays.asList(intervals));
        int count = 0;
        while (!list.isEmpty()) {
            List<Interval> group = new ArrayList<>();
            group.add(list.remove(0)); count++;
            Iterator<Interval> ite = list.iterator();
            while (ite.hasNext()) {
                Interval noGroup = ite.next();
                boolean conflict = false;
                for (Interval inGroup : group) {
                    if (isConflict(inGroup,noGroup)) { conflict = true; break; }
                }
                if (!conflict) {
                    group.add(noGroup);
                    ite.remove();
                }
            }
        }
        return count;
    }

上面的代码通过了 71/77 的测试,但是在 72 号失败了。如果我们不先对区间进行排序,任何人都可以说出它不起作用的原因吗?

【问题讨论】:

  • 实际上您可以在O(n) 中执行此操作,而无需任何复杂的代码。是的,我们也不需要以这种方式进行排序。但是你需要O(max(start,end)) 空间。

标签: algorithm


【解决方案1】:

您不需要对数组进行排序。它可以在 O(n) 时间复杂度内解决。这个想法是创建一个count 数组,并在索引start[i] 处使用+1 更新它,在索引end[i] 处使用-1 对其进行更新。 startend 是会议开始和结束时间对应的数组。

之后,您只需将所有+1-1 相加并形成精确计数数组,然后返回该数组中存在的最大值。下面是伪代码:

int[] count = new int[100];
for(int i=0;i<start.length;i++){
    count[start[i]] += 1;
    count[end[i]] -= 1;
}
//form the count array with exact values in this loop
count[0] = 0;
for(int i =0;i<count.length;i++){
    count[i] = count[i] + count[i-1];
}
return max(count);

【讨论】:

  • 我喜欢这个解决方案。唯一的问题可能是它需要一个非常大的数组 :) 但总的来说这个想法很棒!
  • @weiShen:其实没有。如果你仔细观察你的问题,问题中给出的时间段与一天中的时间有关。因此,可以假定任何值小于 24!因为这些是一天中的时间!我相信这可以利用我们很大的空间! :)
【解决方案2】:

您的“贪婪”算法不会针对某些输入集优化使用房间。它接受在区间列表中找到的第一个拟合。相反,它需要为每个可用的开口采用 最接近 的拟合。实现此目的的一种方法是按开始时间对间隔进行排序;这样,一旦最近的会议完成,它总是会找到最早的可用会议。

例如,生成几组间隔为 1 个单位的会议:例如,3、4、5 和 6 个单位长。

[[1, 3], [4, 6], [7, 9], ...]
[[1, 4], [5, 8], [9, 12], ...]
[[1, 5], [6, 10], [11, 15], ...]
[[1, 6], [7, 12], [13, 18], ...]

按顺序将它们输入您的算法,您将获得最佳的 4 个房间。随机洗牌,你需要 5 或 6 个房间。

【讨论】:

  • 非常感谢!这是一个反例:[[5,10],[1,3],[2,5],[9,12],[10,14],[3,9]] 只需要 2 个房间:[[1,3],[3,9],[9,12]][2,5],[5,10],[10,14]]。但我们会找到 3 个没有排序的房间:[[1,3],[5,10],[10,14]][[2,5],[9,12][[3,9]]
猜你喜欢
  • 2022-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-10
相关资源
最近更新 更多