Pythonで連結リストから指定した値と同じノードをすべて削除する方法
単一連結リストとターゲットとなる値が与えられたとき、リストの中からターゲットと同じ値を持つノードをすべて削除し、残りの連結リストを返すことを考えます。
たとえば、入力が [5,8,2,6,5,2,9,6,2,4] で削除したい値が 2 である場合、出力は [5, 8, 6, 5, 9, 6, 4] となります。
解き方のアルゴリズム
- 変数
headに先頭ノードを保存しておきます。 nodeとnode.nextがどちらも存在する間、以下の処理を繰り返します。node.nextの値がターゲットと等しい間、node.nextをnode.next.nextで置き換えて、該当ノードをリンクから外します。- 1ノード分、
nodeを次へ進めます。
- ループが終了した後、
headの値がターゲットと等しければhead.nextを返します。 - それ以外の場合は、
headをそのまま返します。
実装例
それでは、実際の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, node, target):
head = node
while node and node.next:
while node.next.val == target:
node.next = node.next.next
node = node.next
if head.val == target:
return head.next
else:
return head
ob = Solution()
head = make_list([5,8,2,6,5,2,9,6,2,4])
ob.solve(head, 2)
print_list(head)
入力
[5,8,2,6,5,2,9,6,2,4]
出力
[5, 8, 6, 5, 9, 6, 4]
コードのポイントと注意点
このアルゴリズムのポイントは、内側の while ループによって「ターゲットと同じ値が連続するノード」もまとめて削除できる点です。各ノードを一度だけ走査するため、時間計算量は O(n)、追加のメモリ使用量は O(1) と非常に効率的です。
ただし、上記の実装には1つ注意点があります。先頭ノード自体がターゲットと一致する場合、先頭の1ノードしか削除できません。たとえば [2, 2, 5] のようなリストでは、先頭の 2 が1つ残ってしまいます。
改良版:ダミーノードを使った実装
先頭にダミーノードを追加すれば、先頭ノードがターゲットと一致するケースも含めて、すべて同じ処理で統一的に対応できます。
class Solution:
def solve(self, node, target):
# ダミーノードを先頭に置くことで、先頭の削除にも対応できる
dummy = ListNode(0, node)
curr = dummy
while curr.next:
if curr.next.val == target:
curr.next = curr.next.next
else:
curr = curr.next
return dummy.next
ob = Solution()
head = make_list([2, 5, 8, 2, 6, 2, 9])
result = ob.solve(head, 2)
print_list(result) # [5, 8, 6, 9]
このようにダミーノードを活用すると、エッジケースの処理がシンプルになり、バグの混入を防ぎやすくなります。連結リストの操作では頻繁に使われるテクニックなので、ぜひ覚えておきましょう。
-
Pythonでリンクリストの先頭からk番目と末尾からk番目のノードを交換する方法
問題の概要リンクリスト L と整数 k が与えられたとします。ここで求められているのは、先頭から k 番目のノードと末尾から k 番目のノードを入れ替え、その結果のリンクリストを返すことです。たとえば、入力が L = [1,5,6,7,1,6,3,9,12]、k = 3 の場合を考えてみましょう。先頭から3番目のノードは「6」、末尾から3番目のノードは「3」です。この2つのノードの値を入れ替えると、出力は [1,5,3,7,1,6,6,9,12] となります。解き方のアルゴリズムこの問題は、いわゆる「2つのポインタ(two-pointer)」テクニックを使うことで、リストを一度走査するだけで効
-
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 の場合、出