答えの値で二分探索して締め切りに間に合う最小の速さを探す

何冊かの​本を​決まった​時間で​読み切るのに​要る、​1 時間​あたりの​最小の​ページ数を​返します。​並びではなく​答えの​値の​範囲を​半分ずつ絞る、​二分探索の​使い方の​練習です。

海外で定番の問題リスト 4 本のうち 1 本に入っています (NeetCode 150)

問題

試験の前に、何冊かの本を読み切ろうとしています。各本のページ数を並べた pages と、使える時間 hours (何時間か) を受け取ります。読む速さを 1 時間あたり k ページと決めたとき、次の読み方で hours 時間以内に全部の本を読み切れる、いちばん小さい k を返す関数を書いてください。

  • 1 時間ごとに、読み終えていない本を 1 冊選び、その本を最大 k ページ読みます
  • 選んだ本の残りが k ページより少なければ、その本を読み終えて、その 1 時間の残りは休みます (別の本には移りません)
  • k は 1 以上の整数です
  • pages の長さは 1 以上 10000 以下で、hours は pages の長さ以上 10 億以下です (1 冊に 1 時間かければ、いつかは必ず読み切れます)
  • 各本のページ数は 1 以上 10 億以下です

入力と出力の例

例 1

k が 7 なら、9 ページの本に 2 時間、4 ページに 1 時間、12 ページに 2 時間、7 ページに 1 時間で、合わせて 6 時間です。k が 6 だと 7 時間かかり、間に合いません。

入力

pages = [9, 4, 12, 7]
hours = 6

出力

7

例 2

時間が本の冊数と同じなら、どの本も 1 時間で読み切るしかありません。

入力

pages = [15, 15, 15]
hours = 3

出力

15

例 3

1 冊を 7 時間で読みます。14 ページずつだと 8 時間かかり、15 ページずつなら 7 時間で読み切れます。

入力

pages = [100]
hours = 7

出力

15

面接での聞かれ方

面接では、場面の話 (食べる速さ、運ぶ荷物の量など) で包んで渡されることが多く、二分探索の問題だと気づけるかが最初の関門です。

  • 「締め切りに間に合う、いちばん遅い速さを求めてください」
  • 「速さを 1 から順に試すと、どれくらいかかりますか?」と、素直な書き方の重さを先に聞かれることがあります
  • 書き終えたあとに「二分探索の範囲の上と下は、なぜその値ですか?」「間に合うかどうかが、なぜ速さについて単調なのですか?」と、二分探索を使ってよい理由を聞かれます
  • 同じ型の問題として、「d 日で荷物を運び切れる、船の最小の積める量」などが続けて出ることもあります

ミドルの問題なので、並びの中を探すのではなく「答えの値の範囲」を探すと言えることと、範囲の端と切り上げの割り算を正しく詰めることが見られます。

アルゴリズムのチートシートの「ソートと二分探索」に、​この​型の​要点を​表と​コードで​まとめています。

main.py
def min_reading_speed(pages, hours):
    # ここに書きます
    pass


# 「実行」を押すと、この行の結果が出ます
print(min_reading_speed([9, 4, 12, 7], 6))

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