二分探索で上って下る並びの頂上を探す

上ってから​下る​整数の​並びから、​いちばん高い​所 (頂上) の​位置を​返します。​並び全体が​小さい​順でなくても、​隣と​比べた​向きで​範囲を​半分に​絞れる​ことに​気づく​練習です。

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

問題

整数の並び nums を受け取ります。nums は、ある位置まで値が増え続け、そこから先は減り続ける形をしています。この増加から減少に変わる位置 (頂上) を、0 から数えた番号で返す関数を書いてください。

  • 隣どうしの値は必ず違います。頂上はちょうど 1 つです
  • 増えるだけの並び (頂上は最後) や、減るだけの並び (頂上は最初) もあります。長さが 1 なら頂上は 0 番です
  • nums の長さは 1 以上 1000 以下、値はどれも -2147483648 以上 2147483647 以下です
  • 前から 1 つずつ見る書き方ではなく、並びの長さを n として O(log n) の手間で解いてください

入力と出力の例

例 1

9 まで上り、そこから下ります。9 は 3 番目です。

入力

nums = [1, 4, 7, 9, 6, 2]

出力

3

例 2

最初から下るだけの並びです。頂上は最初の 10 です。

入力

nums = [10, 8, 5, 3]

出力

0

例 3

負の数だけで、上るだけの並びです。頂上は最後の 3 です。

入力

nums = [-5, -2, 0, 3]

出力

3

面接での聞かれ方

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

  • 「山の形の並びの、頂上の位置を返してください」
  • 前から見て下り始めた所を答えると、「O(log n) にできますか?」と続けて聞かれます
  • 「並びが小さい順ではないのに、なぜ二分探索が使えるのですか?」と理由を説明させられます

二分探索は小さい順の並びでしか使えない、と思い込んでいると詰まります。「半分を捨ててよい理由」を言えるかが見られています。

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

main.py
def peak_index(nums):
    # ここに書きます
    pass


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

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