LeetCode 621. Task Scheduler

231 篇文章 0 订阅

Given a char array representing tasks CPU need to do. It contains capital letters A to Z where different letters represent different tasks. Tasks could be done without original order. Each task could be done in one interval. For each interval, CPU could finish one task or just be idle.

However, there is a non-negative cooling interval n that means between two same tasks, there must be at least n intervals that CPU are doing different tasks or just be idle.

You need to return the least number of intervals the CPU will take to finish all the given tasks.

 

Example:

Input: tasks = ["A","A","A","B","B","B"], n = 2
Output: 8
Explanation: A -> B -> idle -> A -> B -> idle -> A -> B.

 

Constraints:

  • The number of tasks is in the range [1, 10000].
  • The integer n is in the range [0, 100].

------------------------------------------

这题反应太慢,刚开始还想着DP,发现状态转移方程太复杂。。。然后又想了很久,才想到CPU流水线,想到按照出现频率最高的贪心。。。最后才想到用优先队列每次扒层皮。。可能一次扒多层或者1层,还写了个bug:

import heapq
class Solution:
    def leastInterval(self, tasks, n: int) -> int:
        td,cycle,last,res = {},n+1,0,0
        for task in tasks:
            td[task] = td.get(task,0)+1
        tv = [-vv for kk,vv in td.items()]
        heapq.heapify(tv)
        while (len(tv) >= cycle):
            topK = []
            for i in range(cycle):
                topK.append(-heapq.heappop(tv))
            delta = topK[-1] if len(tv) >= cycle*2 else 1 #bug1: always topK[-1]
            res += delta*cycle
            for item in topK:
                if (item > delta):
                    heapq.heappush(tv,-(item-delta))
        for j in range(len(tv)):
            if (tv[j] == tv[0]):
                last += 1
        if (tv):
            res += (-tv[0]-1)*cycle+last
        return res

这题更漂亮的解法是用桶的思想,如下图:

如果n=4,那么流水线的cycle=5。那么整个流水线至少要(最长的任务个数-1)*cycle的时间,也就是红框部分,这都好理解

下面开始脑筋急转弯,从流水线空闲的时钟来分析一共所需的时间。

  1. 当任务个数<=cycle时,可能存在流水线空闲的时候,也就是图中的idle,算出idle就可以算整个时间
  2. 当任务个数>cycle时,因为首先会按照每个任务出现频率排序,假设存在idle状态,那么超过cycle的任务一定可以塞到idle状态里。
  3. 当超过cycle的任务持续增多,此时是需要脑筋急转弯的时候,假设所有idle状态都满了。如果把流水线每一个cycle看成一个桶,那么这些桶里之前装的都是互不相同的元素。当新任务来的时候,由于之前预先排序的设定,新任务的个数x一定小等于已有桶的个数,那么从已有x个桶中可以抽出x个互不相同的元素,放到新桶中,旧桶空出来的位置放新来的x个元素。也就是说从此流水线不存在idle的可能。。。

以下是codes:

class Solution:
    def leastInterval(self, tasks, n: int) -> int:
        td, cycle, idle, moretasks, tl = {}, n + 1, 0, 0, len(tasks)
        for task in tasks:
            td[task] = td.get(task, 0) + 1
        tv = [vv for kk, vv in td.items()]
        tv.sort(reverse=True)
        tvl = len(tv)
        if (tvl <= 0):
            return 0
        height = tv[0]-1
        for i in range(1, cycle):
            idle += max(0,height-tv[i]) if i < tvl else height #bug2: forget idle space
        for i in range(cycle, tvl):
            moretasks += tv[i]

        return tl if moretasks >= idle else tl+idle-moretasks #bug1: >= instead of >
s = Solution()
print(s.leastInterval(["A","A","A","A","A","A","B","C","D","E","F","G"],2))


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值