
leetcode 125. valid palindrome

class Solution:
def isPalindrome(self, s: str) -> bool:
left = 0 #왼쪽을 가리키는 포인터 변수
right = len(s)-1 #오른쪽을 가리키는 포인터 변수
s = s.lower()
res = True
while left <= right:
#왼쪽 포인터가 가리키는 변수 값이 숫자, 영문자가 아닐때까지 오른쪽으로 이동
while not (s[left].isalpha() or s[left].isdigit()):
left += 1
if left >= len(s): #범위에 넘어가면 반복 종료
return res
#오른쪽 포인터가 가리키는 변수 값이 숫자, 영문자가 아닐때까지 왼쪽으로 이동
while not (s[right].isalpha() or s[right].isdigit()):
right -= 1
if right < 0: #범위에 넘어가면 반복 종료
return res
if s[left] != s[right]: #두 글자가 다르면 팰린드롬이 아님
res = False
return res
else: #같으면 한 칸 이동
left += 1
right -= 1
return res

책 <파이썬 알고리즘 인터뷰>를 참고함
class Solution:
def isPalindrome(self, s: str) -> bool:
alnum_list = [] #숫자와 영문자만 담을 리스트
for char in s:
if char.isalnum():
alnum_list.append(char.lower()) #소문자로 바꿔서 리스트에 추가
while len(alnum_list) > 1:
if alnum_list.pop() != alnum_list.pop(0):
return False
return True

리스트의 pop()처럼 인덱스번호를 지정 안하면 맨 뒤의 원소를 제거하는데, 이 때는 시간복잡도가 O(1) 이다. 반면에 pop(0)은 길이가 n인 리스트의 맨 앞까지 탐색한 다음에 pop하기 때문에 시간복잡도가 O(n) 이다. 그래서 성능을 확인해보면 좋지 않음을 볼 수 있다.
deque는 파이썬에서 큐를 구현하기 좋은 라이브러리인데, 리스트의 pop(0)과 같은 기능인 popleft()가 있다. 시간복잡도는 O(1)로 훨씬 효율적이다. 리스트를 deque로 바꿔 코드를 다시 작성해보자.
from collections import deque #deque사용을 위해 임포트
class Solution:
def isPalindrome(self, s: str) -> bool:
queue = deque([]) #deque 생성
for char in s:
if char.isalnum():
queue.append(char.lower())
while len(queue) > 1:
if queue.popleft() != queue.pop():
return False
return True

2-1 방법보다는 확실히 빠른 것을 볼 수 있다.
문자.isalnum() 함수는 문자가 영어 혹은 숫자인 경우 true, 아닌 경우는 false를 리턴하는 함수이다. 따라서 전체 문자열에서 문자 하나하나를 체크한다. 문자열 전체에서 통으로 영어와 숫자만 남기는 방법이 있는데, 정규표현식을 사용하면 된다!