Given a string
s
, return the longest palindromic substring ins
.
문자열s
가 주어졌을 때,s
에서 가장 긴 팰린드롬 부분 문자열을 반환
Input: babad
Output: bab
Input: cbbd
Output: bb
Input: a
Output: a
Input: ac
Output: a
Input: xaabacxcabaaxcabaax
Output: xaabacxcabaax
Input: abbbddedssdeeaaas
Output: edssde
Input: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Output: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
abba
, aba
, 가나다라다나가
등def my_longestPalindrome(self, s: str) -> str:
ans = ''
s = "".join(s.split())
print(s)
s_len = len(s)
longestPalindrome = s[0]
longestPalindromeEnd = s_len - 1
longestPalindromeMax = 0
longestPalindromeStart = 0
for i, c in enumerate(s):
start = i
start_old = start
end = s_len - 1
end_old = 0
is_palindrome = False
is_started = False
loop_cnt = 0
if end - start < longestPalindromeMax:
break
while start < end:
first = s[start]
last = s[end]
if first != last:
if is_started:
end = end_old
start = start_old
loop_cnt = 0
is_started = False
is_palindrome = False
longestPalindromeEnd = s_len - 1
longestPalindromeStart = 0
else:
end -= 1
continue
else :
if loop_cnt == 0:
longestPalindromeStart = start
longestPalindromeEnd = end
is_started = True
# 다음에 다시 시작할 end 지점
end_old = end - 1
if is_started:
is_palindrome = True
loop_cnt += 1
start += 1
end -= 1
if is_palindrome:
if longestPalindromeMax < (longestPalindromeEnd - longestPalindromeStart):
longestPalindromeMax = longestPalindromeEnd - longestPalindromeStart
longestPalindrome = "".join(s[longestPalindromeStart:longestPalindromeEnd+1])
return longestPalindrome
접었을 때 좌/우가 서로 들어 맞다
라고 말하자abcdedcba
에서는 e
aaaaabaaa
에서는 a
였다가, 팰린드롬 아니므로 좌 또는 우로 중앙을 이동시킨다aba
에서 중앙은 b
abccba
에서 중앙은? c
와 c
사이def second(self, s: str) -> str:
ans = ''
s_len = len(s)
if s_len == 1:
return s
s_sub_palindrome = ''
s_sub_palindrome_len = 0
loop_cnt = 0
# 중앙을 기점으로 하지 말고 제일 앞에서부터 끝까지 모두 훑어보자
target = s[loop_cnt]
while loop_cnt < s_len:
'''
baaaabb -> baaaab
baaabb -> baaab
'''
print('target: ', target, ', loop_cnt: ', loop_cnt)
idx_curr = loop_cnt
# `aba`: 좌/우에 문자 있고 left와 right는 같고 start는 다른 경우
if idx_curr - 1 >= 0 and idx_curr + 1 < s_len:
loop_cnt_to_add = 1
idx_left = idx_curr - 1
idx_right = idx_curr + 1
is_palindrome = False
while idx_left >= 0 and idx_right < s_len:
if s[idx_left] == s[idx_right]:
idx_left -= 1
idx_right += 1
is_palindrome = True
else:
break
tmp_len = idx_right - idx_left + 1
print('[case1] idx_right: ', idx_right, ', idx_left: ', idx_left, 'tmp_len: ', tmp_len, ', sub str: ', s[idx_left:idx_right + 1])
if is_palindrome and s_sub_palindrome_len < tmp_len:
s_sub_palindrome_len = tmp_len
s_sub_palindrome = s[idx_left + 1:idx_right]
target = s[loop_cnt]
idx_left = idx_curr
idx_right = idx_curr + 1
is_palindrome = False
while idx_left >= 0 and idx_right < s_len:
if s[idx_left] == s[idx_right]:
idx_left -= 1
idx_right += 1
is_palindrome = True
else:
break
tmp_len = idx_right - idx_left + 1
print('[case2] idx_right: ', idx_right, ', idx_left: ', idx_left, 'tmp_len: ', tmp_len, ', sub str: ', s[idx_left:idx_right + 1])
if is_palindrome and s_sub_palindrome_len < tmp_len:
s_sub_palindrome_len = tmp_len
s_sub_palindrome = s[idx_left + 1:idx_right]
loop_cnt_to_add = 2
loop_cnt += loop_cnt_to_add
target = s[loop_cnt]
else:
if s_sub_palindrome_len == 0:
s_sub_palindrome = target
loop_cnt += 1
if loop_cnt < s_len:
target = s[loop_cnt]
ans = s_sub_palindrome
return ans
이 경우 bb
케이스에 b
만 출력한다
1. # 시작부터 문자열 범위 체크
if idx_curr - 1 >= 0 and idx_curr + 1 < s_len:
2. # `aba`: 좌/우에 문자 있고 left와 right는 같고 start는 다른 경우
if s[idx_curr - 1] == s[idx_curr + 1] and target != s[idx_curr - 1]:
3. # `abccba`: 이 경우 첫 c에서 비교하고 다음 c는 건너 띄면 되지 않을까?
if target != s[idx_curr - 1] and target == s[idx_curr + 1]:
abcba
처럼 홀수로 팰린드롬인 경우abccba
처럼 짝수로 팰린드롬인 경우aba
경우, abccba
경우 등을 나눌 필요가 없다.def third(self, s: str) -> str:
print(s)
ans = ''
s_len = len(s)
# 문자열이 1개면 굳이 아래 로직 따를 필요 없다
if s_len == 1:
return s
palindrome_len = 0
loop_cnt = 0
# 중앙을 기점으로 하지 말고 제일 앞에서부터 끝까지 모두 훑어보자
"""
abcddce가 있으면
a -> False
b
-> abc -> False
-> bc -> False
c
-> bcd -> False
-> cd -> False
d
-> cdb -> False
-> db -> True -> cddc -> True -> bcddce -> while문 벗어남
"""
target = s[loop_cnt]
while loop_cnt < s_len:
# 초기값 설정. 이걸 하지 않으면 아래에서 `ac` 같은 경우 빈 값으로 나온다
if palindrome_len == 0 and loop_cnt == 0:
ans = target
# 20210408: 이전에는 당연했던 코드가 오늘은 생소하다. fourth에서 개선
# 홀수개인 경우를 훑어 본다
idx_left = loop_cnt - 1
idx_right = loop_cnt + 1
is_palindrome = False
while idx_left >= 0 and idx_right < s_len:
print("1. s[{}]: {}, s[{}]: {}".format(idx_left, s[idx_left], idx_right, s[idx_right]))
if s[idx_left] == s[idx_right]:
is_palindrome = True
idx_left -= 1
idx_right += 1
else:
break
print('1. is_palindrome: {}'.format(is_palindrome))
if is_palindrome:
tmp_len = idx_right - idx_left + 1
if palindrome_len < tmp_len:
palindrome_len = tmp_len
# while문 안에서 is_palindrome 체크하고 left 및 right로 이동하므로,
# break된 후에는 각각 이전 포인터를 인덱스로 삼아야 한다
ans = s[idx_left + 1:idx_right]
print('1. s[{}:{}] = ans: {}'.format(idx_left + 1, idx_right, ans))
# 짝수개인 경우를 훑어 본다
idx_left = loop_cnt
idx_right = loop_cnt + 1
is_palindrome = False
while idx_left >= 0 and idx_right < s_len:
print("2. s[{}]: {}, s[{}]: {}".format(idx_left, s[idx_left], idx_right, s[idx_right]))
if s[idx_left] == s[idx_right]:
is_palindrome = True
idx_left -= 1
idx_right += 1
else:
break
print('2. is_palindrome: {}'.format(is_palindrome))
if is_palindrome:
tmp_len = idx_right - idx_left + 1
if palindrome_len < tmp_len:
palindrome_len = tmp_len
ans = s[idx_left + 1:idx_right]
print('2. s[{}:{}] = ans: {}'.format(idx_left + 1, idx_right, ans))
loop_cnt += 1
if loop_cnt < s_len:
target = s[loop_cnt]
print("target = s[{}]: {}".format(loop_cnt, target))
else:
break
return ans
Runtime: 760 ms, faster than 90.20% of Python3 online submissions for Longest Palindromic Substring.
Memory Usage: 14.4 MB, less than 63.02% of Python3 online submissions for Longest Palindromic Substring.
def longestPalindrome(self, s: str) -> str:
if len(s) <= 1 or s == s[::-1]:
return s
last_successful_length = 1
last_successful_start = 0
for right in range(1, len(s)):
odd_start = right - last_successful_length - 1
even_start = right - last_successful_length
odd = s[odd_start:right + 1]
even = s[even_start:right + 1]
if odd_start >= 0 and odd == odd[::-1]:
last_successful_start = odd_start
last_successful_length += 2
elif even == even[::-1]:
last_successful_start = even_start
last_successful_length += 1
return s[last_successful_start: last_successful_start + last_successful_length]
def longest_palindrom(s):
# 함수를 완성하세요
return len(s) if s[::-1] == s else max(longest_palindrom(s[:-1]), longest_palindrom(s[1:]))