🐡
234. Palindrome Linked Listを解く
問題概要
単連結リストhead
が与えられる.
このとき,与えられたリストが回文である場合はtrue
そうでない場合はfalse
を返す.
例:
Input: head = [1,2,2,1]
Output: true
制約
- リストに含まれるノードの数
[1,10^5] 0 \leq Node.val \leq 9
考えたこと
head
を前から順にみていき,配列L
にノードの値を格納していく.
ノードの末尾に行き着いたらL == L[::-1]
を評価すれば良いと考えた.
class Solution(object):
def isPalindrome(self, head):
L = []
while head:
L.append(head.val)
head = head.next
return L == L[::-1]
この実装では
従って,何らかの工夫を行い使用メモリを削減する必要がある.
ここでは,2つのポインターを用いて左半分と右半分のノードを比較することで回文かどうか検証する方法を実装する.
まず,ノードの長さが不明な中で左半分と右半分のノードに分けるには
-
fast
,slow
の二つのポインターを用意する -
fast
は1ステップで2ノード進む -
slow
は1ステップで1ノード進む
というように設定すれば良い.
例えば,例に示した問題の場合は
初期状態:
f
1 -> 2 -> 2 -> 1 -> null
s
1ステップ:
f
1 -> 2 -> 2 -> 1 -> null
s
2ステップ:
f
1 -> 2 -> 2 -> 1 -> null
s
のように,ノードの中間点にslow
のポインターが位置していることが分かる.
左半分はhead
を前から順に辿れば良いが,右半分はこのままでは逆順に辿ることになるため,以下のようにノードを反転して再構築する必要がある.
1 -> 2 -> 2 -> 1 -> null
s
1 -> 2 null <- 2 1 -> null
s
1 -> 2 null <- 2 <- 1 null
s
ここまで出来たら左側のノードL
と右側のノードR
を先頭から順に比較して行けば良い.
以上の考えを実装したアルゴリズムを以下に示す:
class Solution(object):
def isPalindrome(self, head):
"""
:type head: ListNode
:rtype: bool
"""
fast = slow = head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
R = None
while slow:
nxt = slow.next
slow.next = R
R = slow
slow = nxt
while R:
if R.val != head.val:
return False
R = R.next
head = head.next
return True
Discussion