二分探索で回された並びから値を探す

小さい​順の​並びを​途中で​切って​前後を​入れ替えた​並びから、​目当ての値の​位置を​ O(log n) で​探します。​半分に​割る​たびに、​どちらの​半分が​順に​並んでいるかを​見分ける​練習です。

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

問題

小さい順に並んだ整数の並びを、どこか 1 か所で切り、後ろの部分を前へ回した並び nums を受け取ります。たとえば [3, 7, 11, 15, 18, 22] を 11 のあとで切ると [15, 18, 22, 3, 7, 11] になります。切らずにそのままのこともあります。整数 target が nums のどこにあるかを探し、その位置 (0 から数えた番号) を返す関数を書いてください。無ければ -1 を返します。

  • nums の値はどれも違います
  • nums の長さは 1 以上 5000 以下、値と target はどれも -10000 以上 10000 以下です
  • 先頭から 1 つずつ見る O(n) ではなく、O(log n) で探してください

入力と出力の例

例 1

22 のあとで小さい値に戻る並びです。7 は前から 5 番目にあります。

入力

nums = [15, 18, 22, 3, 7, 11]
target = 7

出力

4

例 2

25 は並びにありません。

入力

nums = [30, 40, 10, 20]
target = 25

出力

-1

例 3

値が 1 つだけの並びです。

入力

nums = [6]
target = 6

出力

0

面接での聞かれ方

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

  • 「ソート済みの配列を回転させた物から、値を探してください。O(log n) でお願いします」
  • 最初に O(n) の書き方を出すと、「並びの形をもう少し使えませんか?」と寄せられます
  • 書き終えたあとに「同じ値が入っていてもよいとしたら、どこが壊れますか?」「切れ目の位置だけを返せますか?」と広げて聞かれます

二分探索の問題では、lo と hi が閉じた区間か開いた区間かを最初に決めて口に出すと、終わりの条件で迷いません。

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

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


# 「実行」を押すと、この行の結果が出ます
print(search_rotated([15, 18, 22, 3, 7, 11], 7))

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