1ポインタ・インプレース走査 による O(n) / O(1) 実装
ソート済み単方向連結リストの先頭ノード
head
を受け取り、 各要素がちょうど 1 回だけ現れるようにリストを変更して返す。
ソート済みであるという特性から、重複は必ず隣接して現れる。 これにより 1
パスの線形走査で解決できる。
current
を進めてはいけない(3連続重複を見逃す)
head is None と
head.next is None
の両方をガード
リストが空(None)、またはノードが1つ(head.next is None)なら重複は存在しない。即 head を返して終了(緑の矢印)。
current.next is None
になったらループ終了(緑矢印 → return)。current.next
が存在する間は内部処理を継続(下方向)。
current.val == nxt.val なら
current.next = nxt.next で
nxt を切り離す。current は移動せず、ループ先頭へ戻って再チェック(紫の破線)。
current.val != nxt.val なら
current = nxt
で1つ前進。ループ先頭へ戻って次のノードを比較(紫の破線)。
| 指標 | 値 | 理由 |
|---|---|---|
| 時間計算量 | O(n) |
各ノードを最大 1 回走査。重複スキップ時も
current は移動しないが、next
の参照が前進するため全体では O(n)
|
| 空間計算量 | O(1) |
スタック変数 current /
nxt のみ。新規ノード生成ゼロ
|
| ヒープ確保 | 0 回 |
既存ノードの
next
付け替えのみ。新オブジェクト生成なし
|
| アプローチ | Time | Space | 特徴 |
|---|---|---|---|
| ✅ 1ポインタ・インプレース(本実装) | O(n) | O(1) | 最適。ヒープ確保ゼロ |
| 再帰 | O(n) | O(n) | 可読性高いがコールスタック消費 |
| 配列変換+再構築 | O(n) | O(n) | 不要なオブジェクト生成多数 |