ソートで順序を作る

並べ替えると「近い値」「小さい順」が見えるようになります。元の順序が意味を持つ問題では保存しましょう。

言語:Python / 計算量:O(N log N)

前提:全探索は「漏れなく、重複なく」

考え方

  1. sorted(a) は新しいリストを返します。
  2. a.sort() は a 自体を並べ替えます。
  3. 同じ値が複数ある場合、何番目の要素かと何種類目かは別です。

具体例

[7,2,5] → [2,5,7]。隣同士の差は3と2。最小の差は2です。

実装

a = sorted([7, 2, 5])
print(min(a[i+1] - a[i] for i in range(len(a)-1)))

注意する条件

a = a.sort() と書くと a は None になります。

確認問題

[9,1,5] を昇順にした中央の値は?

解答と理由

5

並べると [1,5,9] です。

実装課題

N と N 個の整数 A が2行。異なる添字の2要素の差の絶対値の最小値。2 ≤ N ≤ 200000、|A_i| ≤ 10^9。

入力:
3
7 2 5
出力:
2
参考実装
n = int(input())
a = sorted(map(int, input().split()))
print(min(a[i+1] - a[i] for i in range(n-1)))

実戦につなげる補講

一度に全て読まなくて大丈夫です。今日は1節と1問から。

順序を変えてよいか、先に確認する

位置関係が答えに必要なら、無条件にソートしてはいけません。元の時刻順・隣接関係・部分列などを壊す場合があります。順序が不要か、添字を一緒に持てば復元できるかを考えます。

並べ替えは「以降を見る必要がない」を作る

昇順なら、しきい値未満と以上が連続した領域になります。これは二分探索の入口です。最も差が小さい2要素も、同じ列ならソート後の隣り合う要素を調べれば足ります。間に要素がある2点より、途中の隣接差のどれかが大きくなることはありません。

ソート代を忘れない

ソート後の走査がO(N)でも、全体にはソートのO(N log N)が含まれます。a.sort()は元の列を変更し、sorted(a)は新しい列を作ります。Pythonのソートも作業領域を使うので、追加メモリが常にO(1)とは考えません。

段階式の追加演習

1. 使えない条件

入力された順番で隣り合う2人の年齢差を求めたい。年齢順にソートしてよい?

ヒント

「隣」の意味が変わらないか。

解答と理由

不可。入力順の隣接関係が問題の条件なので、ソートすると別の問いになる。

2. 実装:一番近い2値

要素数2以上の整数列aから、異なる添字の2値の差の絶対値の最小を返すnearestを書いて。a=[18,3,12,13]なら1。

ヒント

ソート後の隣接差を調べる。

解答と理由

O(N log N)で並べ、N−1箇所だけ比較する。値が重複していれば0。

def nearest(a):
    b = sorted(a)
    return min(b[i + 1] - b[i] for i in range(len(b) - 1))

3. 1つの列と2つの列の違い

2つの列から1つずつ選ぶとき、両列を混ぜて単純に最小の隣接差を取ってよい?

ヒント

同じ列の要素同士が選ばれていないか。

解答と理由

不可。所属する列のラベルを保持して異なる列同士に限定するなど、元の条件を守る必要がある。

4. 計算量を合算

長さNの列を1回ソートし、その後Q回二分探索する。全体の計算量は?

ヒント

前処理と質問を別々に数える。

解答と理由

O(N log N+Q log N)。質問のたびにソートするとO(QN log N)になってしまう。

公式過去問への橋渡し

ABC212 C / 公式解説

2つの列から選ぶ全組合せは最大400億組。ソート後に比較対象を減らす判断を練習する。

公式問題 / 公式解説

見本を閉じて確認

読了の記録・下書き・メモへ