最小ヒープで点を含む最も短い区間を答える

区間問題 162

電波の届く範囲の並びと、問い合わせの地点の並びから、地点ごとにそこへ届く範囲のうち最も短い物の長さを返す。範囲と地点をどちらも左から並べ、届き始めた範囲を長さの短い順のヒープに入れていけば、地点ごとにヒープの根を見るだけで答えが出ます。

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

問題

まっすぐな道に沿って、基地局の電波の届く範囲が [左端, 右端] の組の並び ranges で渡されます。範囲は左端と右端の両方を含み、範囲の長さは 右端 - 左端 + 1 です。問い合わせの地点の並び points も渡されます。地点ごとに、その地点を含む範囲のうち長さが最も短い物の長さを求め、points と同じ順に並べて返す関数を書いてください。

  • 地点を含む範囲が 1 つも無ければ、その地点の答えは -1 です
  • ranges も points も並べ替えられていません。points には同じ値が何度も出ることがあります
  • どの組も、左端は右端以下です
  • ranges と points の長さはどちらも 1 以上 100000 以下、値はどれも 1 以上 10000000 以下です

入力と出力の例

例 1

地点 4 には [1, 6] (長さ 6) と [3, 4] (長さ 2) が届くので 2 です。地点 8 には [8, 8] (長さ 1) が届くので 1、地点 2 には [1, 6] だけで 6、地点 10 にはどれも届かないので -1 です。

ranges = [[1, 6], [3, 4], [5, 9], [8, 8]] points = [4, 8, 2, 10]
[2, 1, 6, -1]

例 2

同じ地点を何度聞かれても、同じ答えを返します。地点 1 にはどれも届きません。

ranges = [[2, 7], [4, 5]] points = [5, 5, 1]
[2, 2, -1]

例 3

地点 20 は [10, 20] の右端なので、まだ届いています。地点 21 では [10, 20] が外れ、[15, 30] の 16 だけが残ります。

ranges = [[10, 20], [15, 30]] points = [20, 21, 15]
[11, 16, 11]

面接での聞かれ方

面接では、区間とヒープを組み合わせる上の段の問題として出されることが多いです。

  • 「区間の並びと問い合わせの並びがあります。問い合わせごとに、それを含む最も短い区間の長さを答えてください」
  • 「1 つずつ全部の区間を調べてもよいですか」と聞くと、「どちらも 10 万個あります」と返ってくるのがふつうです
  • 書き終えたあとに「問い合わせが 1 つずつ届き、先を読めないならどうしますか」と、続きを聞かれることもあります

問い合わせを先に全部受け取れるかどうかで、解き方が変わります。書く前に確かめておきます。

ヒント

まだ開いていません

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

  1. ヒント 2

  2. ヒント 3答えに近い

アルゴリズムのチートシートの「配列と文字列」に、この型の要点を表とコードでまとめています。

配列と文字列の問題は、全部の組を調べると手間が大きくなる所を、窓や左右の添字で減らす形が多いです。

main.py
def smallest_interval(ranges: list[list[int]], points: list[int]) -> list[int]:
    """
    Goal: 何を返すか

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

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

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


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

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