输入:
第一行输入总共的任务数量m
接下来m行,每行两个数字,表示任务的截止时间和该任务的收益(1单位时间可以完成一个任务)
输出:
最大的收益
这类题往往采用贪心+优先队列的思想进行求解,代码如下:
from heapq import *
m = int(input())
arr = []
for _ in range(m):
arr.append(list(map(int, input().split())))
def funer(arr):
arr.sort()
pq = [arr[0][1]]
heapify(pq)
for i in range(1, len(arr)):
heappush(pq, arr[i][1]) # 按截止时间先后顺序,存储任务的收益值
# 如果当前时刻任务的截止时间和上一时刻任务的截止时间相同:
# 如果此时优先队列的任务数量大于当前任务的截止时间
# 则需要将队列里最小收益弹出(表示不选择该任务)
# 不好理解的话,这里取[1,19],[1,25]为例,当i==2,此时pq = [19, 25],这两个任务的截止时间都是1,len(pq) > 1,所以需要将收益值19这个任务抛弃。
if arr[i][0] == arr[i - 1][0]:
if len(pq) > arr[i][0]:
heappop(pq)
# print(i, pq)
res = 0
# 最后队列里面的收益值所对应的任务即为所选的任务
while pq:
res += heappop(pq)
return res
out = funer(arr)
print(out)
'''
5
2 100
1 19
2 27
1 25
3 13
out:
140
'''
其他类似的题型:
最多可以参加的会议数目
# 核心思想就是把每个开始时间不大于当前时间(i)的结束时间放到堆中,然后判断结束时间是不是大于当前,
# 不是直接扔掉,是就扔掉答案的同时记录一次答案。
class Solution:
def maxEvents(self,events):
res, T = 0, 0
d = collections.defaultdict(list)
for s, e in events:
d[s].append(e)
T = max(T, e)
q = []
for i in range(1, T + 1):
for end in d[i]:
heapq.heappush(q, end)
del d[i] # 优化字典,将此刻时间的会议去掉
while q:
cur = heapq.heappop(q) #结束时间比当前开始时间早的都弹出
if cur >= i: # 找到符合条件的,则更新res,跳出循环
res += 1
break
return res
吃苹果的最大数目
# 优先吃掉最早过期的苹果
from heapq import *
class Solution:
def eatenApples(self, apples: List[int], days: List[int]) -> int:
q, res, i = [], 0, 0
n = len(apples)
while i < n or q:
if i < n and apples[i] > 0:
heappush(q, [i + days[i], apples[i]])
while q and (q[0][0] <= i or q[0][1] <= 0):
heappop(q)
if q:
q[0][1] -= 1
res += 1
i += 1
return res
2022一点资讯某题
给定一天的时间段数组,在每个时间段内参加一个活动,求这一天最多可以参加几个活动。(开始时间一定是早于结束时间,如果前一个活动在某一时刻结束,可以再去参加同一时刻开始的另一个活动)
输入:
times = [[“10:00”,“12:00”],[“03:00”,“11:30”],[“11:30”,“14:00”]]
输出:
2
(核心代码模式)
这题的所有案例有点意外,当时一直没思路,就直接return了数组长度减一,结果100%通过哈哈哈哈。
这题与区间合并也有点类似,就是求最多有多少个不相交的区间个数,上面几题区间是可以相交的。该题其实就是lc上的原题:
无重叠区间
该题可以用dp求解,跟俄罗斯套娃、最长递增子序列dp方法求解一样,但会超时!
因此采用第二种方法,核心思路就是:
1. 按照结束时间从小到大排序,然后对新列表进行遍历;
2. 判断当前区间是否满足:开始时间晚于或者等于上一次的结束时间;
3. 每次都选结束时间最早的;
4. 每选一次更新一下结束时间.
这题思路与前面的相反,选择的是以结束时间进行排序从小到大排序!!!
# # DP[i]以i下标区间结尾的最大不重合区间个数
# class Solution:
# def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
# if not intervals: return 0
# intervals.sort()
# n = len(intervals)
# dp = [1] * n
# for i in range(1, n):
# for j in range(i):
# if intervals[i][0] >= intervals[j][1]:
# dp[i] = max(dp[i], dp[j] + 1)
# return n - max(dp)
# 贪心
class Solution:
def eraseOverlapIntervals(self, intervals):
end, cnt = float('-inf'), 0
for s, e in sorted(intervals, key=lambda x: x[1]):
if s >= end:
end = e
else:
cnt += 1
return cnt
与该题相似的题还有以下几题:
用最少数量的箭引爆气球
# 按照左坐标从小到大排序
class Solution:
def findMinArrowShots(self, points: List[List[int]]) -> int:
points.sort()
n = len(points)
res, e = n, points[0][1]
for i in range(1, n):
if points[i][0] <= e:
res -= 1
e = min(points[i][1], e)
else:
e = points[i][1]
return res
# # 按照右坐标从小到大排序
class Solution:
def findMinArrowShots(self, points: List[List[int]]) -> int:
points.sort(key = lambda x : x[1])
n = len(points)
res, e = 1, points[0][1]
for p in points:
if p[0] > e:
res += 1
e = p[1]
return res
会议室II
给定一个会议时间安排的数组,每个会议时间都会包括开始和结束的时间 [[s1,e1],[s2,e2],…] (si < ei),为避免会议冲突,同时要考虑充分利用会议室资源,请你计算至少需要多少间会议室,才能满足这些会议安排。
示例 1:
输入: [[0, 30],[5, 10],[15, 20]]
输出: 2
示例 2:
输入: [[7,10],[2,4]]
输出: 1
参考讲解
这个问题有一个非常简单的处理思路,我们可以先将上述的区间在坐标轴上画好,然后通过垂直于x轴的线从左向右移动,移动的过程中,记录这根线和区间相交的最大交点个数,这个最大交点个数就是相交的最大区间个数。
算法的实现上我们有一个trick,我们遍历intervals中的每一项it,然后对于左边的坐标用[it[0], 1]表示(表示我们进入一个线段),右边的坐标用[it[1], -1]表示(表示我们退出了一个线段),然后将这些新得到的区间加入到一个tmp数组中,对这个数组排序,接着遍历这个数组,遍历的过程中累加我们建立的标记位(也就是前面建立的1和-1)记录累加的最大值即可。
代码如下:
class Solution:
def minMeetingRooms(self, intervals):
if not intervals:
return 0
tmp = sorted(x for i, j in intervals for x in [[i, 1], [j, -1]])
res, n = 0, 0
for i, v in tmp:
n += v
res = max(res, n)
return res
另外还可以用优先队列进行求解:
- 首先进行一下排序,然后用一个小顶堆,维护当前每个会议室的结束时间,然后当一个新的时间安排出现的时候,只需要判断一下是否需要新申请一个会议室,还是继续使用之前的会议室。
from heapq import *
class Solution:
def minMeetingRooms(self, intervals):
intervals.sort()
pq = []
for i in range(len(intervals)):
if pq and pq[0] <= intervals[i][0]:
heappop(pq)
heappush(pq, intervals[i][1])
return len(pq)