Pythonでソート済み双方向連結リストから積が指定値と一致するペアを検索する方法
一意な正の整数で構成されたソート済みの双方向連結リスト(doubly linked list)があるとします。このリストの中から、積が指定された値 x と一致するペアを見つける必要があります。重要なポイントは、余分なメモリ領域を消費せずに解くことです。
例えば、入力が次のような場合を考えてみましょう。
L = 1 ⇔ 2 ⇔ 4 ⇔ 5 ⇔ 6 ⇔ 8 ⇔ 9、x = 8
このとき、出力は (1, 8) と (2, 4) になります。
アルゴリズムの考え方:二ポインタ手法
この問題は、配列の「二ポインタ(two pointer)」テクニックを連結リストに応用することで、O(n) の時間計算量・O(1) の空間計算量で解けます。手順は以下の通りです。
currを先頭ノードに、nxtも先頭ノードに設定する。nxt.nextが None になるまでnxtを末尾まで進める(末尾ノードへのポインタを取得)。- フラグ
foundを False で初期化する。 currとnxtがどちらも有効で、かつ互いに異なり、nxt.nextがcurrではない間、以下を繰り返す。curr.data * nxt.data == xの場合:
foundを True にし、ペア(curr.data, nxt.data)を表示して、currを次へ、nxtを前へ移動する。- 積が
xより小さい場合:
積を大きくするためにcurrを次のノードへ進める。 - 積が
xより大きい場合:
積を小さくするためにnxtを前のノードへ戻す。
- ループ終了後も
foundが False の場合は、「Not found(見つかりません)」と表示する。
リストが昇順にソートされているため、「先頭から進むポインタ」と「末尾から戻るポインタ」を使うことで、積の大小関係に応じて効率的に探索範囲を絞り込めるのがこの手法のポイントです。
Pythonでの実装例
それでは、実際のコードを見てみましょう。
class ListNode:
def __init__(self, data):
self.data = data
self.prev = None
self.next = None
def insert(head, data):
node = ListNode(data)
node.next = node.prev = None
if head is None:
head = node
else:
node.next = head
head.prev = node
head = node
return head
def get_pair_prod(head, x):
curr = head
nxt = head
# 末尾ノードまで移動
while nxt.next is not None:
nxt = nxt.next
found = False
while curr is not None and nxt is not None \
and curr != nxt and nxt.next != curr:
if curr.data * nxt.data == x:
found = True
print("(", curr.data, ",", nxt.data, ")")
curr = curr.next
nxt = nxt.prev
elif curr.data * nxt.data < x:
curr = curr.next
else:
nxt = nxt.prev
if not found:
print("Not found")
# リストの構築
head = None
for val in [9, 8, 6, 5, 4, 2, 1]:
head = insert(head, val)
x = 8
get_pair_prod(head, x)
入力
head = None head = insert(head, 9) head = insert(head, 8) head = insert(head, 6) head = insert(head, 5) head = insert(head, 4) head = insert(head, 2) head = insert(head, 1) x = 8
出力
( 1 , 8 ) ( 2 , 4 )
計算量について
- 時間計算量: O(n)。各ポインタは最大でもリスト全体を一度ずつ走査するためです。
- 空間計算量: O(1)。追加のデータ構造を使用しないため、問題の制約「余分な領域を使わない」を満たしています。
このように、双方向連結リストの prev ポインタを活用すれば、ハッシュセットなどを使わずに、ソート済みリスト上で効率的にペア検索を行うことができます。
-
ソート済み双方向連結リストで積が指定値xと等しくなるトリプルの個数を数えるC++プログラム
問題の概要 整数値を格納したソート済みの双方向連結リスト(doubly linked list)が与えられます。この課題の目標は、3つのノードのデータの積が指定された値xと等しくなるようなトリプル(三つ組)の個数を求めることです。 例えば、入力リンクリストが「3→4→1→2」でxが6の場合、積が6になるトリプルは(3, 1, 2)の1つだけなので、カウントは1となります。 入力例と出力例 例1 入力: linked list: [ 200→4→16→5→10→10→2 ]、x = 200 出力: 積が指定値xと等しくなるトリプルの個数: 3 説明: 該当するトリプルは以下の3つです。 (4
-
Pythonで二分木の中に連結リストと一致するパスが存在するか判定する方法
問題の概要根ノード「root」を持つ二分木と、先頭ノード「head」を持つ連結リストが与えられたとします。このとき、連結リストが二分木の中に存在するかどうかを判定します。具体的には、木の中の一連のノードが親から子へと順番につながっており、その並びが与えられた連結リストと完全に一致する場合には「True」を返し、一致しない場合には「False」を返します。例えば、入力が以下のようなケースを考えてみましょう。二分木連結リストこの場合、二分木の中に 6 → 7 → 10 という並びのパスが存在するため、出力は True になります。解法のアプローチこの問題は、文字列検索アルゴリズムとして有名なKMP