[ LeetCode #234 ] Palindrome Linked List 팰린드롬 연결 리스트 #
[ LeetCode #234 ] Palindrome Linked List 바로가기 #
💡 유용한 지식 #
러너 기법
- 연결 리스트를 순회할 때 2개의 포인터를 동시에 사용하는 기법
- 빠른 러너와 느린 러너를 생성하여 병합 지점이나 중간 위치, 길이 등을 판별할 때 유용
- 빠른 러너가 연결 리스트의 끝에 도달하면 느린 러너는 연결 리스트의 중간 지점을 가리키게 되어 중간 위치를 찾아내면 값 비교하거나 뒤집기를 시도하는 등 다각도로 활용이 가능
## runner 기법 # - fast, slow 는 모두 Linked List # - fast 에 값이 있다면 길이가 홀수인 경우이므로 한칸 더 전진시킨다. while fast and fast.next: fast = fast.next.next history, history.next, slow = slow, history, slow.next if fast: slow = slow.next
다중 할당 (Multiple Assignment)
- 파이썬은 원시 타입이 존재하지 않고 모든 것이 객체
- 줄을 구분해서 할당하면 history = slow 구문으로 인해 같은 객체를 참조를 할당하므로 줄을 나누는 것과 한번에 처리하는 것은 다른 풀이가 된다.
history, history.next, slow = slow, history, slow.next
문제 #
Given the head
of a singly linked list, return true
if it is a palindrome.
Constraints:
- The number of nodes in the list is in the range
[1, 105]
. 0 <= Node.val <= 9
Follow up:
Could you do it in O(n) time and O(1) space?
내가 했던 접근 #
[ 풀이 ]
- 리스트에 append 후 슬라이싱으로 판별하기
[ 결과 ]
Runtime: 1214 ms, faster than 68.41% of Python online submissions for Palindrome Linked List. Memory Usage: 85.6 MB, less than 17.58% of Python online submissions for Palindrome Linked List.
[ 코드 ]
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):
def isPalindrome(self, head):
history = list()
if head.next is None:
return True
while head:
history.append( head.val )
head = head.next
return history == history[::-1]
[ 반성 ]
- linked list 특성을 살리지 못한 풀이
책 풀이 #
[ 풀이 ]
- 방법 1 : list + pop(0) (내 접근과 유사)
- 나는 팰린드롬 판별을 리스트 슬라이싱으로 했지만 pop(0)을 사용
- 방법 2 : deque + popleft()
- 방법 1 은 pop(0) 으로 조회가 O(n)이었지만 데크 자료형으로 O(1)로 조회 가능
- 방법 3 : 러너 **
- fast, slow 러너 2가지를 만들고 fast는 두칸씩, slow는 한칸씩 전진시켜 fast가 끝에 도달할때 slow를 중간지점에 위치시킨다.
- slow가 오면서 지나친 길을 역순으로 history를 만들고 만약 길이가 홀수였으면 slow 를 한칸 더 전진 시킨다.
- slow의 중간을 지나친 값과 역순으로 기록해둔 history의 값을 차례로 비교한다.
- 모두 일치하여 slow가 None이 되면 True, 아니면 False 반환
[ 결과 ]
방법 1 : list + pop(0) (내 접근과 유사)
Runtime: 1690 ms, faster than 23.68% of Python online submissions for Palindrome Linked List.
Memory Usage: 84.7 MB, less than 46.59% of Python online submissions for Palindrome Linked List.
방법 2 : deque + popleft()
Runtime: 1469 ms, faster than 41.47% of Python online submissions for Palindrome Linked List. Memory Usage: 84.5 MB, less than 51.87% of Python online submissions for Palindrome Linked List.
방법 3 : (연결리스트 특성 활용한 방법) 러너 (992 ms)**
Runtime: 992 ms, faster than 93.93% of Python online submissions for Palindrome Linked List.
Memory Usage: 49.6 MB, less than 96.18% of Python online submissions for Palindrome Linked List.
[ 코드 ]
방법 1 : list + pop(0) (1690 ms)
class Solution(object):
def isPalindrome(self, head):
history = list()
if head.next is None:
return True
while head:
history.append( head.val )
head = head.next
while len(history) > 1 :
if history.pop(0) != history.pop():
return False
return True
방법 2 : deque + popleft() (1469 ms)
from collections import deque
class Solution(object):
def isPalindrome(self, head):
history = deque()
if head.next is None:
return True
while head:
history.append( head.val )
head = head.next
while len(history) > 1 :
if history.popleft() != history.pop():
return False
return True
방법 3 : (연결리스트 특성 활용한 방법) 러너 (992 ms)**
class Solution(object):
def isPalindrome(self, head):
history = None
fast = slow = head
while fast and fast.next:
fast = fast.next.next
history, history.next, slow = slow, history, slow.next
if fast:
slow = slow.next
while history and history.val == slow.val:
history, slow = history.next, slow.next
return not slow