Python
 Computer >> コンピューター >  >> プログラミング >> Python

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] が得られています。

  1. 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 の場合、出

  2. 【Python入門】2つの文字列から珍しい単語(ユニークな単語)を見つけるプログラムの作り方

    はじめに この記事では、以下の問題文に対する解決方法を、実際のコード例とともにわかりやすく解説します。 問題文 2つの文字列が与えられたとき、その中から「珍しい単語」(どちらか一方の文字列にしか出現しない単語)をすべて抽出することを目標とします。両方の文字列に共通して含まれる単語は除外します。 解決のアプローチ ここでは辞書(dict)を使った出現回数のカウント方式を採用します。手順は次のとおりです。 空の辞書を用意する 各文字列をsplit()で単語ごとに分割する 各単語の出現回数を辞書に記録する 出現回数がちょうど1回の単語だけを結果として返す 実装例 # 珍しい単語を見つける関