


难度似乎很大,分数2381,评级8,但是看了提示发现暴力是可以做出来的,因为数据只在$10^3$量级。
按照提示的思路,把数组倒序排序,然后按照每个任务的结束时将向前递推,枚举时间点直到当前任务完成。如此暴力的方法竟然做出来了,纪念一下自己这辈子第一次做出的hard
自己的代码
class Solution:
def findMinimumTime(self, tasks: List[List[int]]) -> int:
tasks_sorted = sorted(tasks, key = lambda p : p[1])
n = len(tasks)
ans = 0
t_list = []
for i in range(n):
# 每个任务按完成时间从后往前遍历
t = tasks_sorted[i][1]
while tasks_sorted[i][2]!=0:
if t not in t_list:
tasks_sorted[i][2] -= 1
# print(t)
ans +=1
t_list.append(t)
for j in range(i+1,n):
if tasks_sorted[j][0]<=t and tasks_sorted[j][1]>=t and tasks_sorted[j][2]>0:
tasks_sorted[j][2]-=1
t-=1
return ans
大佬的思路
暴力思路:
class Solution:
def findMinimumTime(self, tasks: List[List[int]]) -> int:
tasks.sort(key=lambda t: t[1])
run = [False] * (tasks[-1][1] + 1)
for start, end, d in tasks:
d -= sum(run[start: end + 1]) # 去掉运行中的时间点
if d <= 0: # 该任务已完成
continue
# 该任务尚未完成,从后往前找没有运行的时间点
for i in range(end, start - 1, -1):
if run[i]: # 已运行
continue
run[i] = True # 运行
d -= 1
if d == 0:
break
return sum(run)
class Solution:
def findMinimumTime(self, tasks: List[List[int]]) -> int:
tasks.sort(key=lambda t: t[1])
run = [False] * (tasks[-1][1] + 1)
for start, end, d in tasks:
d -= sum(run[start: end + 1]) # 去掉运行中的时间点
if d <= 0: # 该任务已完成
continue
# 该任务尚未完成,从后往前找没有运行的时间点
for i in range(end, start - 1, -1):
if run[i]: # 已运行
continue
run[i] = True # 运行
d -= 1
if d == 0:
break
return sum(run)
线段树思路:
线段树的讲解文章:https://zhuanlan.zhihu.com/p/106118909
周末在咖啡厅摁刷线段树,在力扣从简单的开始做
class Solution:
def findMinimumTime(self, tasks: List[List[int]]) -> int:
tasks.sort(key=lambda t: t[1])
u = tasks[-1][1]
m = 2 << u.bit_length()
cnt = [0] * m
todo = [False] * m
def do(o: int, l: int, r: int) -> None:
cnt[o] = r - l + 1
todo[o] = True
def spread(o: int, l: int, m: int, r: int) -> None:
if todo[o]:
todo[o] = False
do(o * 2, l, m)
do(o * 2 + 1, m + 1, r)
# 查询区间正在运行的时间点 [L,R] o,l,r=1,1,u
def query(o: int, l: int, r: int, L: int, R: int) -> int:
if L <= l and r <= R: return cnt[o]
m = (l + r) // 2
spread(o, l, m, r)
if m >= R: return query(o * 2, l, m, L, R)
if m < L: return query(o * 2 + 1, m + 1, r, L, R)
return query(o * 2, l, m, L, R) + query(o * 2 + 1, m + 1, r, L, R)
# 在区间 [L,R] 的后缀上新增 suffix 个时间点 o,l,r=1,1,u
# 相当于把线段树二分和线段树更新合并成了一个函数,时间复杂度为 O(log u)
def update(o: int, l: int, r: int, L: int, R: int) -> None:
size = r - l + 1
if cnt[o] == size: return # 全部为运行中
nonlocal suffix
if L <= l and r <= R and size - cnt[o] <= suffix: # 整个区间全部改为运行中
suffix -= size - cnt[o]
do(o, l, r)
return
m = (l + r) // 2
spread(o, l, m, r)
if m < R: update(o * 2 + 1, m + 1, r, L, R) # 先更新右子树
if suffix: update(o * 2, l, m, L, R) # 再更新左子树(如果还有需要新增的时间点)
cnt[o] = cnt[o * 2] + cnt[o * 2 + 1]
for start, end, d in tasks:
suffix = d - query(1, 1, u, start, end) # 去掉运行中的时间点
if suffix > 0: update(1, 1, u, start, end) # 新增时间点
return cnt[1]
法三:栈+二分查找
class Solution:
def findMinimumTime(self, tasks: List[List[int]]) -> int:
tasks.sort(key=lambda t: t[1])
# 栈中保存闭区间左右端点,栈底到栈顶的区间长度的和
st = [(-2, -2, 0)] # 哨兵,保证不和任何区间相交
for start, end, d in tasks:
_, r, s = st[bisect_left(st, (start,)) - 1]
d -= st[-1][2] - s # 去掉运行中的时间点
if start <= r: # start 在区间 st[i] 内
d -= r - start + 1 # 去掉运行中的时间点
if d <= 0:
continue
while end - st[-1][1] <= d: # 剩余的 d 填充区间后缀
l, r, _ = st.pop()
d += r - l + 1 # 合并区间
st.append((end - d + 1, end, st[-1][2] + d))
return st[-1][2]
有点累了,来不及看,先粘上,日后再说。
怎么收藏这篇文章?
看的我热血沸腾啊https://www.jiwenlaw.com/