面试高频区间调度类问题总结 interval scheduling

首先分析一下区间类问题:

  1. 一般都有时间顺序,
  2. 有开始和结束。
  3. 是一个vector,包含了这些开始时间和结束时间

解法总结:

  1. 最容易想到的就是要对时间进行排序。可能是对开始时间进行排序,也可能是对结束时间进行排序。 比如meeting room, 问一个人能不能参加所有meeting,只需要对开始时间进行排序,然后检查前面的结束,和后面的开始是不是冲突就能解决了。
  2. 扫描线算法,碰到一个start就+1, 碰到一个end就-1。 这个算法挺简单,可以想象成同时有多少会议在进行,开始一个就加一,结束一个就减一。 最大值就是meeting room ii 的答案,最多需要多少meeting room。
  3. 在排序之上,比如meeting room ii,用priority queue,对结束时间进行排序,然后就按照开始时间一个个对比。我们的目标是让pq记录在用的会议室的结束时间。 所以最后pq的size就是我们要的答案。
  • 如果当前开始时间比pq上最早的结束时间要晚,那说明这两个可以共用一个会议室呀。那就pop掉这个结束时间,push 上新的结束时间。pq的长度不变。
  • 如果当前开始时间小于pq上最早时间,那说明会议室不够用了,连最早结束时间都满足不了,其他肯定也不行,直接push上新的结束时间。pq长度+1
  • 一直到最后一个区间,pq长度在这段时间只增加不减少。

4. 贪心算法:始终选择具有最早结束时间的区间。然后就能获得最大数量的不重叠区间。因为具有最早结束时间的区间产生了最大的容纳其余区间的能力。

  • 比如当前剩余区间的最早结束时间是x。可用于其他区间的时间段就是[x:]。如果我们选择另一个结束时间为y的区间,那么可用时间段将变为[y:]。由于x ≤ y,因此没有办法使[y:]比[x:]容纳更多的区间。所以这个贪心算法可以hold。
  • 因此可以按结束时间对区间进行排序,并跟踪当前最早的结束时间。一旦下一个区间的开始时间早于当前结束时间,我们就必须移除一个区间。否则,就更新最早的结束时间。

56. Merge Intervals 中等题 面试出现28次

这道题是做到现在为止出现次数最多的题了。。

也是之前入职华为的时候算法面试考的一道题的变形,真的巧了。当时考的是meeting room II, 给一堆meeting时间问需要多少会议室。正好也是谷歌高频题。

这里的做法是先对区间进行排序,然后开始遍历,记录开始和结尾。 如果新的开始在前一个结尾的前面,那就更新结尾。否则加入结果vector。

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {

        if (intervals.size() <= 1) {
            return intervals;
        }

        vector<vector<int>> ans;
        sort(intervals.begin(), intervals.end());
        int left = intervals[0][0];
        int right = intervals[0][1];

        for (int i = 1; i < intervals.size(); i++) {
            int new_left = intervals[i][0];
            int new_right = intervals[i][1];
            if (new_left <= right) {
                right = max(right, new_right);
            } else {
                ans.push_back({left, right});
                left = new_left;
                right = new_right;
            }
        }
        ans.push_back({left, right});
        return ans;
    }
};

252 meeting room 简单题

给很多interval,问能不能参加全部会议,很简单,只需要sort之后判断有没有开始和结尾重合就好了。

因为没有leetcode 会员,所以用的lintcode。 但是lintcode 的interval是一个class,所以需要写一个lambda function,不能直接sort。

/**
 * Definition of Interval:
 * class Interval {
 * public:
 *     int start, end;
 *     Interval(int start, int end) {
 *         this->start = start;
 *         this->end = end;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param intervals: an array of meeting time intervals
     * @return: if a person could attend all meetings
     */
    bool canAttendMeetings(vector<Interval> &intervals) {
        // Write your code here
        sort(intervals.begin(), intervals.end(), [](const Interval& a, const Interval& b){return a.start < b.start;});
        int newBegin;
        int lastEnd = -1;

        for (int i = 0; i < intervals.size(); i++) {
            newBegin = intervals[i].start;
            if (intervals[i].start < lastEnd) {
                return false;
            }
            lastEnd = intervals[i].end;
        }
        return true;
    }
};

253 meeting room II 中等题

问需要几间会议室。

min heap 解法(chatGPT)

class Solution {
public:
    int minMeetingRooms(vector<vector<int>>& intervals) {
        if (intervals.empty()) {
            return 0;
        }

        // Sort the intervals based on start time
        sort(intervals.begin(), intervals.end(), [](const auto& a, const auto& b) {
            return a[0] < b[0];
        });

        // Use a min heap to keep track of end times of meetings
        priority_queue<int, vector<int>, greater<int>> endTimes;

        // Iterate through the intervals
        for (const auto& interval : intervals) {
            // If the next meeting starts after the earliest ending meeting,
            // remove the earliest ending meeting (pop from min heap)
            if (!endTimes.empty() && interval[0] >= endTimes.top()) {
                endTimes.pop();
            }

            // Add the current meeting's end time to the min heap
            endTimes.push(interval[1]);
        }

        // The size of the min heap represents the minimum number of meeting rooms required
        return endTimes.size();
    }
};

比较经典的扫描线的题,解法非常得简单

class Solution {
public:
    /**
     * @param intervals: an array of meeting time intervals
     * @return: the minimum number of conference rooms required
     */
    int minMeetingRooms(vector<Interval> &intervals) {
        // Write your code here
        vector<pair<int,int>> sweepline;
        for (auto it : intervals) {
            sweepline.push_back(make_pair(it.start, 1));
            sweepline.push_back(make_pair(it.end, -1));
        }
        sort(sweepline.begin(), sweepline.end());

        int room = 0;
        int pre_sum = 0;
        for (auto dot : sweepline) {
            pre_sum += it.second;
            room = max(room, pre_sum);
        }

        return room;

    }
};

435 Nonoverlaping Intervals 中等题

给定一些interval,找出最少删除多少interval才能让剩下的都是non overlap。

class Solution {
public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {

        sort(intervals.begin(), intervals.end());

        int start = intervals[0][0];
        int end = intervals[0][1];
        int res = 0;

        for (int i = 1; i < intervals.size(); i++) {
            if (intervals[i][0] >= end) {
                end = intervals[i][1];
                continue; 
            } else {
                end = min(intervals[i][1], end);
                res++;
            }
        }
        return res;
        
    }
};

452. Minimum Number of Arrows to Burst Balloons 中等题

X轴上有很多气球,每个气球占一个范围[x1, x2],气球范围可以有重叠,沿着y轴射箭,问最少射多少支箭可以射穿所有的气球。

按结尾sort,这道题就变成easy题了。只要后面的开始在前面的结束之后就+1 就可以。

class Solution {
public:
    int findMinArrowShots(vector<vector<int>>& points) {
        if (points.empty()) return 0;
    
    // Sort the intervals based on their ending points
    sort(points.begin(), points.end(), [](const vector<int>& a, const vector<int>& b) {
        return a[1] < b[1];
    });
    
    int arrows = 1; // Initialize with 1 because we always need at least one arrow
    int prevEnd = points[0][1]; // Initialize with the ending point of the first interval
    
    for (int i = 1; i < points.size(); ++i) {
        if (points[i][0] > prevEnd) {
            // The current interval does not overlap with the previous one
            // We need to use another arrow
            arrows++;
            prevEnd = points[i][1];
        }
    }
    
    return arrows;
    }
};

1288 Remove Covered Intervals 中等题

求去掉所有被cover的 interval剩下的数量,区间完全被包括了的叫做covered。

class Solution {
public:
    int removeCoveredIntervals(vector<vector<int>>& intervals) {

        sort(intervals.begin(), intervals.end());
        int start = -1;
        int end = -1;
        int res = 0;
        for (int i = 0; i < intervals.size(); i++) {
            // if ==start, > end, this is a larger interval, previous one is covered.
            // if >= start, <= end, this is a covered interval. 
            // only situation left is > start and > end
            if (intervals[i][0] > start && intervals[i][1] > end) {
                res++;
                start = intervals[i][0];
            }
            end = max(intervals[i][1], end);
        }
        return res;
        
    }
};

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值