Given an array of intervals intervals where intervals[i] = [starti, endi], return the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping.
Example 1:
Input: intervals = [[1,2],[2,3],[3,4],[1,3]]
Output: 1
Explanation: [1,3] can be removed and the rest of the intervals are non-overlapping.
Example 2:
Input: intervals = [[1,2],[1,2],[1,2]]
Output: 2
Explanation: You need to remove two [1,2] to make the rest of the intervals non-overlapping.
A classic greedy case: interval scheduling problem.
The heuristic is: always pick the interval with the earliest end time. Then you can get the maximal number of non-overlapping intervals. (or minimal number to remove).
This is because, the interval with the earliest end time produces the maximal capacity to hold rest intervals.
E.g. Suppose current earliest end time of the rest intervals is x. Then available time slot left for other intervals is [x:]. If we choose another interval with end time y, then available time slot would be [y:]. Since x ≤ y, there is no way [y:] can hold more intervals then [x:]. Thus, the heuristic holds.
Therefore, we can sort interval by ending time and key track of current earliest end time. Once next interval’s start time is earlier than current end time, then we have to remove one interval. Otherwise, we update earliest end time.
time: O(n logn) for sorting the array, then N to iterate
space: O(n) bc standard python sorting takes N space, we also copy the interval array. we could implement QS to get log(n) space
class Solution:
Given an array of meeting time intervals where intervals[i] = [starti, endi], determine if a person could attend all meetings.
Example 1:
Input: intervals = [[0,30],[5,10],[15,20]]
Output: false
Example 2:
Input: intervals = [[7,10],[2,4]]
Output: true
A classic greedy case: interval scheduling problem.
The heuristic is: always pick the interval with the earliest end time. Then you can get the maximal number of non-overlapping intervals. (or minimal number to remove).
This is because, the interval with the earliest end time produces the maximal capacity to hold rest intervals.
E.g. Suppose current earliest end time of the rest intervals is x. Then available time slot left for other intervals is [x:]. If we choose another interval with end time y, then available time slot would be [y:]. Since x ≤ y, there is no way [y:] can hold more intervals then [x:]. Thus, the heuristic holds.
Therefore, we can sort interval by ending time and key track of current earliest end time. Once next interval’s start time is earlier than current end time, then we have to remove one interval. Otherwise, we update earliest end time.
time: O(n logn), sorted takes that time
space: O(n), sorted takes N space in python, but quick sort could take log n time.
class Solution:
Given an array of meeting time intervals intervals where intervals[i] = [starti, endi], return the minimum number of conference rooms required.
Example 1:
Input: intervals = [[0,30],[5,10],[15,20]]
Output: 2
Example 2:
Input: intervals = [[7,10],[2,4]]
Output: 1
5 15, 10 15, 15 25, 16 27 is the edge case that we cant use the same logic as non-overlapping-intervals. it evaluates 3 rooms (bc we start at 1 room, and would have 2 that mee the bad conditions, making it 3 total rooms, answer is 2)
time: O(n log N) for sorting, then N for iteration
space: O(n), sorting can take N time and the heap is N
import heapq
class Solution:
—-def minMeetingRooms(self, intervals):
——–if not len(intervals):
————return 0
——–
——–rooms = []
——–intervals.sort()
——–
——–heapq.heappush(rooms, intervals[0][1])
——–
——–for i in range(1, len(intervals)):
————if rooms[0] <= intervals[i][0]:
—————-heapq.heappop(rooms)
————
————heapq.heappush(rooms, intervals[i][1])
——–
——–return len(rooms)
time: O(n log N) for sorting, then N for iteration
space: O(n), sorting can take N time and the heap is N
Given an array of intervals where intervals[i] = [starti, endi], merge all overlapping intervals, and return an array of the non-overlapping intervals that cover all the intervals in the input.
Example 1:
Input: intervals = [[1,3],[2,6],[8,10],[15,18]]
Output: [[1,6],[8,10],[15,18]]
Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6].
Example 2:
Input: intervals = [[1,4],[4,5]]
Output: [[1,5]]
Explanation: Intervals [1,4] and [4,5] are considered overlapping.
non-overlapping intervals method has an interesting heuristic that only finds the “bad” intervals, it has no good way of using that information for anything else
time: O(n log n) to sort, the n to iterate
space: O(n) for python, but we can do sorting in logN time with quick sort or constant with heap
class Solution: ----def merge(self, intervals): --------if not intervals: ------------return [] --------intervals.sort(key=lambda x: x[0]) -------- --------output = [intervals[0][:]] --------out_index = 0 --------end = intervals[0][1] -------- --------for i, interval in enumerate(intervals[1:], start=1): ------------start, end2 = interval # 1,4 and 4,5 are considered overlapping in this case! why idfk ------------if end < start: ----------------out_index += 1 ----------------output.append(intervals[i][:]) ------------end = max(end, end2) ------------output[out_index][1] = end --------return output
Given an array of intervals where intervals[i] = [starti, endi], merge all overlapping intervals, and return an array of the non-overlapping intervals that cover all the intervals in the input.
Example 1:
Input: intervals = [[1,3],[2,6],[8,10],[15,18]]
Output: [[1,6],[8,10],[15,18]]
Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6].
Example 2:
Input: intervals = [[1,4],[4,5]]
Output: [[1,5]]
Explanation: Intervals [1,4] and [4,5] are considered overlapping.
non-overlapping intervals method has an interesting heuristic that only finds the “bad” intervals, it has no good way of using that information for anything else
time: O(n log n) to sort, the n to iterate
space: O(n) for python, but we can do sorting in logN time with quick sort or constant with heap
class Solution: ----def merge(self, intervals): --------if not intervals: ------------return [] --------intervals.sort(key=lambda x: x[0]) -------- --------output = [intervals[0][:]] --------out_index = 0 --------end = intervals[0][1] -------- --------for i, interval in enumerate(intervals[1:], start=1): ------------start, end2 = interval # 1,4 and 4,5 are considered overlapping in this case! why idfk ------------if end < start: ----------------out_index += 1 ----------------output.append(intervals[i][:]) ------------end = max(end, end2) ------------output[out_index][1] = end --------return output
You are given an array of non-overlapping intervals intervals where intervals[i] = [starti, endi] represent the start and the end of the ith interval and intervals is sorted in ascending order by starti. You are also given an interval newInterval = [start, end] that represents the start and end of another interval.
Insert newInterval into intervals such that intervals is still sorted in ascending order by starti and intervals still does not have any overlapping intervals (merge overlapping intervals if necessary).
Return intervals after the insertion.
Example 1:
Input: intervals = [[1,3],[6,9]], newInterval = [2,5]
Output: [[1,5],[6,9]]
Example 2:
Input: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
Output: [[1,2],[3,10],[12,16]]
Explanation: Because the new interval [4,8] overlaps with [3,5],[6,7],[8,10].
class Solution:
time: O(n), it comes sorted. If we had to sort it ourselves, we would have to perform merge interval problem first, then do this
space: O(n), for the response
class Solution:
——–return response