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

Pythonで片方向リンクリストの中央ノードを1回の走査で見つける方法

片方向リンクリスト(単方向連結リスト)の先頭ノードが与えられたとき、その中央ノードの値を求めることを考えます。ノード数が偶数で中央にあたるノードが2つ存在する場合は、後ろ側(2番目)の中央ノードを返すものとします。さらに、リスト全体をたどるのは1回だけ(シングルパス)で解くのが条件です。

例えば、入力が [5,9,6,4,8,2,1,4,5,2] の場合、要素数は10なので中央は「8」と「2」の2つになります。したがって、出力は後ろ側の 2 となります。

解法のアプローチ

この問題は、基準点となるポインタ p をゆっくり進めながら、カウンタを組み合わせて処理することで解けます。手順は以下の通りです。

  • p を先頭ノードに設定し、カウンタ d と l をそれぞれ 0 で初期化します。
  • node が null になるまで、次の処理を繰り返します。
    • d が 2 以外の場合:node を次のノードへ進め、l と d をそれぞれ 1 ずつ増やします。
    • d が 2 の場合:p を次のノードへ進め、d を 0 に戻します。
  • ループ終了後、l が奇数であれば p の値を、偶数であれば p の次のノードの値を返します。

それでは、実際の実装例を見てみましょう。

実装例

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

class Solution:
   def solve(self, node):
      p = node
      d = 0
      l = 0
      while node:
         if d != 2:
            node = node.next
            l += 1
            d += 1
         else:
            p = p.next
            d = 0
      return p.val if l & 1 else p.next.val

ob = Solution()
head = make_list([5,9,6,4,8,2,1,4,5,2])
print(ob.solve(head))

入力

[5,9,6,4,8,2,1,4,5,2]

出力

2

よりシンプルな別解:低速・高速ポインタ(Runner法)

同じ問題は、いわゆる「低速・高速ポインタ」を使うとより簡潔に書けます。slow ポインタは1つずつ、fast ポインタは2つずつ進めます。fast がリストの末尾に到達したとき、slow はちょうど中央(偶数長の場合は後ろ側の中央)に位置しています。

class Solution:
   def solve(self, node):
      slow = fast = node
      while fast and fast.next:
         slow = slow.next
         fast = fast.next.next
      return slow.val

ob = Solution()
head = make_list([5,9,6,4,8,2,1,4,5,2])
print(ob.solve(head))

どちらの手法も計算量は O(n)、追加メモリは O(1) であり、シングルパスの条件を満たします。実務やコーディング面接では、可読性の高い Runner法が好まれることが多いです。

  1. Pythonでリスト内の最小値を見つける方法を解説

    この記事では、リストの中から最小の数値を見つける方法について、具体的なサンプルコードとともに詳しく解説します。問題の概要問題: 数値のリストが与えられたとき、その中に含まれる最も小さい数値を画面に表示すること。この問題を解くアプローチは主に2つあります。ひとつは sort() メソッドを使ってリストを昇順に並べ替え、先頭の要素(インデックス0)を取得する方法。もうひとつは、Pythonに標準で用意されている組み込み関数 min() を使う方法です。それぞれ順番に見ていきましょう。方法1:sort()メソッドで並べ替えて最小値を取得するまずはリストを昇順にソートし、先頭の要素を取り出す方法です。

  2. Pythonでリスト内の最大値を見つける方法をわかりやすく解説

    この記事では、Pythonを使ってリストの中から最大の要素(最大値)を見つける方法について解説します。初心者の方でも理解しやすいよう、複数のアプローチをコード例とともに紹介していきます。 問題の概要 問題文: 与えられたリストの中から、最も大きい要素を求めて出力してください。 Pythonには便利な組み込み関数が用意されているため、これらを活用することで短いコードで効率的に問題を解決できます。ここでは主に sort() メソッドと max() 関数の2つの方法を取り上げます。 方法1:sort() 関数を使う sort() メソッドはリストを昇順に並べ替えます。並べ替え後のリストの末尾(インデ