ヒープで同じ作業の間を空けて全部を終える最短の時間を求める

ヒープ問題 111

同じ種類の作業のあいだに決まった数の休みを挟む決まりで、全部の作業を終えるのに要るいちばん短い時間を数えます。残りの多い作業から先に入れる欲張りを、大きい順のヒープで回す練習です。

海外で定番の問題リスト 4 本には入っていません

問題

1 台の焼き窯で、器を 1 つずつ焼きます。焼く器の種類を英大文字 1 字で書いた並び tasks を受け取ります。窯は 1 単位の時間に、器を 1 つ焼くか、何もせず休むかのどちらかをします。同じ種類の器を続けて焼くと割れやすいので、同じ種類の器を焼いたあとは、そのあいだに少なくとも gap 単位の時間 (ほかの種類を焼くか休む) を空けます。全部の器を焼き終えるのに要る、いちばん短い時間を返す関数を書いてください。

  • 器はどんな順で焼いてもかまいません
  • tasks の長さは 1 以上 10000 以下、字は "A" から "Z" のどれかです
  • gap は 0 以上 100 以下の整数です

入力と出力の例

例 1

A B C A B 休 A の順で焼くと 7 単位で終わります。A が 3 つあり、A と A のあいだに 2 単位ずつ要るので、7 より短くはできません。

tasks = ["A", "A", "A", "B", "B", "C"] gap = 2
7

例 2

gap が 0 なら休みは要らず、器の数の 6 単位で終わります。

tasks = ["A", "A", "A", "B", "B", "C"] gap = 0
6

例 3

A B C D A B C のように並べると、休みを入れずに 7 単位で焼けます。種類が多いと、休みは要りません。

tasks = ["A", "A", "B", "B", "C", "C", "D"] gap = 1
7

面接での聞かれ方

面接では、短く次のように渡されることが多いです。

  • 「CPU の仕事の並びと冷却の時間 n があります。同じ仕事のあいだに n 単位を空けるとき、全部を終える最短の時間は?」
  • ヒープで書くと「どうして残りの多い仕事から入れるのですか?」と、欲張りが正しい理由を聞かれます
  • 書き終えたあとに「式 1 本で求められますか?」と聞かれることがあります

返すのが「並べた順」ではなく「時間の長さ」だけであることを最初に確かめると、何を数えればよいかが決まります。

ヒント

まだ開いていません

付箋は 4 枚。下の段ほど答えに近づきます

  1. ヒント 2

  2. ヒント 3

  3. ヒント 4答えに近い

アルゴリズムのチートシートの「スタックとキュー」に、この型の要点を表とコードでまとめています。

スタックは後から入れた物を先に、キューは先に入れた物を先に取り出します。括弧の対応や、順番待ちの処理の形です。

main.py
def least_time(tasks: list[str], gap: int) -> int:
    """
    Goal: 何を返すか

    idea1: まず思いつく案
    -> runtime: O(?)  space: O(?)

    idea2: もっと速い案
    -> runtime: O(?)  space: O(?)

    edge case: 空、1 つだけ、など
    """
    # ここに書きます
    pass


# 「実行」を押すと、この行の結果が出ます
print(least_time(["A", "A", "A", "B", "B", "C"], 2))

できているか「例で確かめる」を押すと、問題の例を全部この関数に渡して、通ったかをここに出します