Pythonで2つのソート済み連結リストの交差(共通要素)を求めるプログラム
問題の概要
2つのソート済み連結リスト(リンクリスト)L1 と L2 が与えられたとき、両方のリストに共通して含まれる要素だけからなる、新しいソート済み連結リストを作成することを考えます。これは、いわゆる「リストの交差」を求める問題です。
例えば、入力が L1 = [2, 4, 8]、L2 = [3, 4, 8, 10] の場合、両方のリストに存在する要素は 4 と 8 のみなので、出力は [4, 8] になります。
解き方のアプローチ
両方のリストがすでにソートされているため、各リストの先頭から2つのポインタを同時に進めていくことで、効率的に共通要素を抽出できます。具体的な手順は以下の通りです。
- 値 0 を持つダミーノードを作成し、head とします。
- cur に head を代入します。
- l1 と l2 のどちらも空でない間、以下の処理を繰り返します。
- l1 の値が l2 の値より小さい場合:l1 を次のノードへ進めます。
- l2 の値が l1 の値より小さい場合:l2 を次のノードへ進めます。
- それ以外(両者の値が等しい場合):cur の next として l1 と同じ値を持つ新しいノードを作成し、l1・l2・cur をそれぞれ次へ進めます。
- ループが終わったら、head.next を返します(ダミーノードを除いた結果のリスト)。
リストの長さをそれぞれ n、m とすると、計算量は O(n + m) となり、各ノードを一度ずつしか走査しないため非常に効率的です。また、ダミーノードを使用することで、結果リストの先頭の扱いがシンプルになり、コード全体も読みやすくなります。
実装例
それでは、上記の手順をPythonで実装したコードを見てみましょう。
class ListNode:
def __init__(self, data, next = None):
self.val = data
self.next = next
def make_list(elements):
head = ListNode(elements[0])
for element in elements[1:]:
ptr = head
while ptr.next:
ptr = ptr.next
ptr.next = ListNode(element)
return head
def print_list(head):
ptr = head
print('[', end = "")
while ptr:
print(ptr.val, end = ", ")
ptr = ptr.next
print(']')
class Solution:
def solve(self, l1, l2):
head = cur = ListNode(0)
while l1 and l2:
if l1.val < l2.val:
l1 = l1.next
elif l2.val < l1.val:
l2 = l2.next
else:
cur.next = ListNode(l1.val)
l1 = l1.next
l2 = l2.next
cur = cur.next
return head.next
ob = Solution()
L1 = make_list([2, 4, 8])
L2 = make_list([3, 4, 8, 10])
print_list(ob.solve(L1, L2))
入力
[2, 4, 8], [3, 4, 8, 10]
出力
[4, 8]
出力の末尾に余分なカンマが表示されるのは、print_list 関数が各要素の後にカンマを出力する仕様になっているためです。リストの内容としては、正しく共通要素の [4, 8] が得られています。
-
Pythonで連結リストのm個のノードを保持した後にn個のノードを削除するプログラム
始点ノードが「head」である連結リストと、2つの整数 m と n が与えられたとします。リストを走査しながら、先頭から数えて m 個のノードを残した直後の n 個のノードを削除する処理を、連結リストの末尾に到達するまで繰り返します。処理は head ノードから開始し、最後に変更後の連結リストを返します。今回扱う連結リストの構造は次のように定義されています。Node value : <整数値> next : <次のノードへのポインタ>例えば、入力が elements = [1, 2, 3, 4, 5, 6, 7, 8]、m = 3、n = 1 の場合、出
-
【Python入門】2つの文字列から珍しい単語(ユニークな単語)を見つけるプログラムの作り方
はじめに この記事では、以下の問題文に対する解決方法を、実際のコード例とともにわかりやすく解説します。 問題文 2つの文字列が与えられたとき、その中から「珍しい単語」(どちらか一方の文字列にしか出現しない単語)をすべて抽出することを目標とします。両方の文字列に共通して含まれる単語は除外します。 解決のアプローチ ここでは辞書(dict)を使った出現回数のカウント方式を採用します。手順は次のとおりです。 空の辞書を用意する 各文字列をsplit()で単語ごとに分割する 各単語の出現回数を辞書に記録する 出現回数がちょうど1回の単語だけを結果として返す 実装例 # 珍しい単語を見つける関