二分探索で同じ値が続く範囲の両端を探す

小さい​順に​並んだ​整数の​並びから、​目標の​値が​続いている​範囲の​最初と​最後の​位置を​返します。​「この​値以上が​始まる​位置」を​探す二分探索を​ 2 回使い、​端の​場合まで​詰める​練習です。

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

問題

小さい順に並んだ整数の並び nums と、整数 target を受け取ります。nums の中で値が target の所は、並んでいるので必ずひとつながりになります。その最初の位置と最後の位置 (0 から数えた番号) を [最初, 最後] の形で返す関数を書いてください。

  • nums は小さい順に並んでいます。同じ値が続くこともあります
  • target が nums に無いときは [-1, -1] を返します。nums が空のときも同じです
  • nums の長さは 0 以上 100000 以下、値と target はどれも -1000000000 以上 1000000000 以下です
  • 前から 1 つずつ見る書き方ではなく、並びの長さを n として O(log n) の手間で解いてください

入力と出力の例

例 1

4 は 1 番目から 3 番目まで続いています。

入力

nums = [2, 4, 4, 4, 7, 9]
target = 4

出力

[1, 3]

例 2

6 は並びにありません。5 と 8 の間に入るはずの値です。

入力

nums = [1, 3, 5, 8]
target = 6

出力

[-1, -1]

例 3

並びが全部 6 です。範囲は端から端までになります。

入力

nums = [6, 6, 6]
target = 6

出力

[0, 2]

面接での聞かれ方

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

  • 「並んだ数の中で、ある値が出てくる範囲を返してください。O(log n) でお願いします」
  • 最初に前から数える書き方を答えると、「同じ値が 10 万個続いたらどうなりますか?」と聞き返されます
  • 書き終えたあとに「その値がいくつあるかも O(log n) で数えられますか?」と続けて聞かれることがあります

二分探索は、どこで止めるかの 1 字の違いで結果が変わります。探す物を「ちょうど等しい位置」ではなく「この値以上が始まる位置」と言い直してから書くと、迷いが減ります。

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

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


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

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