621. 任务调度器 中等

给你一个用字符数组 tasks 表示的 CPU 需要执行的任务列表。其中每个字母表示一种不同种类的任务。任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完。在任何一个单位时间,CPU 可以完成一个任务,或者处于待命状态。

然而,两个 相同种类 的任务之间必须有长度为整数 n 的冷却时间,因此至少有连续 n 个单位时间内 CPU 在执行不同的任务,或者在待命状态。

你需要计算完成所有任务所需要的 最短时间 。

示例 1:

输入:tasks = ["A","A","A","B","B","B"], n = 2
输出:8
解释:A -> B -> (待命) -> A -> B -> (待命) -> A -> B
     在本示例中,两个相同类型任务之间必须间隔长度为 n = 2 的冷却时间,而执行一个任务只需要一个单位时间,所以中间出现了(待命)状态。 

示例 2:

输入:tasks = ["A","A","A","B","B","B"], n = 0
输出:6
解释:在这种情况下,任何大小为 6 的排列都可以满足要求,因为 n = 0
["A","A","A","B","B","B"]
["A","B","A","B","A","B"]
["B","B","B","A","A","A"]
...
诸如此类

示例 3:

输入:tasks = ["A","A","A","A","A","A","B","C","D","E","F","G"], n = 2
输出:16
解释:一种可能的解决方案是:
     A -> B -> C -> A -> D -> E -> A -> F -> G -> A -> (待命) -> (待命) -> A -> (待命) -> (待命) -> A

提示:

  • 1 <= task.length <= 104
  • tasks[i] 是大写英文字母
  • n 的取值范围为 [0, 100]

代码参考:

package main

import (
    "fmt"
    "sort"
    "strings"
)

func main() {
    fmt.Println(leastInterval([]byte{'A', 'A', 'A', 'B', 'B'}, 2))
}

// 思路:从高频字母开始
// A _ _ A _ _ A _ _
// A B _ A B _ A _ _
// A B _ A B _ A        // bingo
func leastInterval(tasks []byte, n int) int {
    m := make(map[byte]int)
    for _, t := range tasks {
        m[t]++
    }

    counts := make(map[int][]byte)
    for b, count := range m {
        counts[count] = append(counts[count], b) // 统计各字母的出现频率
    }

    var freqs []int
    for c := range counts {
        freqs = append(freqs, c)
    }
    sort.Ints(freqs)

    maxFreq := freqs[len(freqs)-1]
    c := maxFreq * (n + 1)
    holders := make([]byte, c) // 占位 // 注意遍历顺序是不定的
    for i := range holders {
        if i%(n+1) == 0 {
            holders[i] = counts[maxFreq][0] // 初始化占位数组
        }
    }
    counts[maxFreq] = counts[maxFreq][1:]

    // 从后向前遍历字符,填充
    var cs []int
    for count := range counts {
        cs = append(cs, count)
    }
    sort.Ints(cs)

    // debug(holders)

    for i := len(cs) - 1; i >= 0; i-- {
        c = cs[i]
        bs := counts[c]
        for _, b := range bs {
            for start, h := range holders {
                if h == 0 { // 向后占位
                    for i := start; c >= 0 && i < len(holders); c-- {
                        holders[i] = b
                        i += n + 1
                    }
                    break
                }
            }
        }
    }

    holders = trimRight(holders)
    debug(holders) // A B 0 A B 0 A B

    return len(holders) // 8
}

func trimRight(bs []byte) []byte {
    for i := len(bs) - 1; i >= 0; i-- {
        if bs[i] == byte(0) {
            bs = bs[:i]
        } else {
            break
        }
    }
    return bs
}

func debug(bs []byte) {
    s := string(bs)
    s = strings.Replace(s, "\x00", "0", -1)
    fmt.Println(strings.Join(strings.Split(s, ""), " "))
}
最后编辑: kuteng  文档更新时间: 2021-06-05 10:16   作者:kuteng