Skip to content

Commit d033c2a

Browse files
committed
solve(w08): 647. Palindromic Substrings
1 parent cb252a1 commit d033c2a

File tree

1 file changed

+116
-0
lines changed

1 file changed

+116
-0
lines changed

palindromic-substrings/seungriyou.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# https://leetcode.com/problems/palindromic-substrings/
2+
3+
class Solution:
4+
def countSubstrings_dp(self, s: str) -> int:
5+
"""
6+
[Complexity]
7+
- TC: O(n^2)
8+
- SC: O(n^2)
9+
10+
[Approach]
11+
palindromic substring인지 여부를 확인하기 위해, 크게 두 가지 경우에 대해 고려해야 한다.
12+
- 길이가 홀수: len == 1인 단위 substring에서 좌우로 확장
13+
- 길이가 짝수: len == 2인 단위 substring에서 좌우로 확장
14+
15+
이때, 기존의 짧은 substring에서 판단한 결과를 계속해서 재사용하므로 다음의 DP table을 사용하는 2D DP로 풀 수 있다.
16+
dp[i][j] = s[i:j + 1]이 palindromic substring인지 여부
17+
18+
따라서 다음과 같이 1) & 2)에서 길이가 각각 1, 2인 단위 substring에 대해 초기화를 먼저 수행하고, 3)에서 len >= 3이상인 substring에 대해 판단한다.
19+
단, **더 짧은 안 쪽 substring에서의 판단 결과를 사용해야 하므로** len을 3부터 n까지 늘려가면서, two pointer i & j로 판단한다.
20+
1) length = 1 : dp[i][i]은 무조건 True
21+
2) length = 2 : dp[i][i + 1]은 s[i] == s[i + 1]이면 True
22+
3) length >= 3 : (j = i + length - 1일 때) dp[i][j]은 (s[i] == s[j]) && (dp[i + 1][j - 1])이면 True
23+
"""
24+
25+
n = len(s)
26+
dp = [[False for _ in range(n)] for _ in range(n)]
27+
res = 0
28+
29+
# 1) length = 1 : dp[i][i]은 무조건 True
30+
for i in range(n):
31+
dp[i][i] = True
32+
res += 1
33+
34+
# 2) length = 2 : dp[i][i + 1]은 s[i] == s[i + 1]이면 True
35+
for i in range(n - 1):
36+
if s[i] == s[i + 1]:
37+
dp[i][i + 1] = True
38+
res += 1
39+
40+
# 3) length >= 3 : (j = i + length - 1일 때) dp[i][j]은 s[i] == s[j]이면서 dp[i][j - 1]이면 True
41+
for length in range(3, n + 1): # length는 3부터 n까지 늘려나가기 (**더 짧은 substring에서의 판단 결과를 사용해야 하므로**)
42+
for i in range(n - length + 1): # i = substring 시작 인덱스
43+
j = i + length - 1 # j = substring 종료 인덱스
44+
if s[i] == s[j] and dp[i + 1][
45+
j - 1]: # (1) i & j가 가리키는 문자가 서로 같고 (2) 안 쪽 substring이 palindrome 이라면 palindromic substring
46+
dp[i][j] = True
47+
res += 1
48+
49+
return res
50+
51+
def countSubstrings_dp2(self, s: str) -> int:
52+
"""
53+
[Complexity]
54+
- TC: O(n^2)
55+
- SC: O(n^2)
56+
57+
[Approach]
58+
length <= 2 조건을 or 연산으로 연결함으로써 1), 2), 3) 케이스를 하나로 줄일 수 있다.
59+
"""
60+
61+
n = len(s)
62+
dp = [[False for _ in range(n)] for _ in range(n)]
63+
res = 0
64+
65+
for length in range(1, n + 1): # length는 1부터 n까지 늘려나가기 (**더 짧은 substring에서의 판단 결과를 사용해야 하므로**)
66+
for i in range(n - length + 1): # i = substring 시작 인덱스
67+
j = i + length - 1 # j = substring 종료 인덱스
68+
if s[i] == s[j] and (length <= 2 or dp[i + 1][j - 1]): # length <= 2 조건을 or 연산으로 연결
69+
dp[i][j] = True
70+
res += 1
71+
72+
return res
73+
74+
def countSubstrings(self, s: str) -> int:
75+
"""
76+
[Complexity]
77+
- TC: O(n^2)
78+
- SC: O(1)
79+
80+
[Approach]
81+
palindromic substring인지 여부를 확인하기 위해, 크게 두 가지 경우에 대해 고려해야 한다.
82+
- 길이가 홀수: len == 1인 단위 substring에서 좌우로 확장
83+
- 길이가 짝수: len == 2인 단위 substring에서 좌우로 확장
84+
85+
따라서 s를 순회하며, 각 문자를 center로 하여 만들 수 있는 길이가 홀수 & 짝수인 palindrome의 개수를 좌우로 확장해가며 카운트한다.
86+
"""
87+
88+
def count_palindrome_from_center(lo, hi):
89+
cnt = 0
90+
91+
# lo와 hi가 범위를 벗어나지 않도록
92+
while (lo >= 0 and hi < len(s)):
93+
# lo와 hi가 가리키는 문자가 다르다면 더이상 확장하며 palindrome을 찾을 수 없음
94+
if s[lo] != s[hi]:
95+
break
96+
97+
# lo와 hi를 좌우로 확장
98+
lo -= 1
99+
hi += 1
100+
101+
# palindrome 개수 증가
102+
cnt += 1
103+
104+
return cnt
105+
106+
res = 0
107+
108+
# center 인덱스 순회
109+
for i in range(len(s)):
110+
# 길이가 홀수: len == 1인 단위 substring에서 좌우로 확장
111+
res += count_palindrome_from_center(i, i)
112+
113+
# 길이가 짝수: len == 2인 단위 substring에서 좌우로 확장
114+
res += count_palindrome_from_center(i, i + 1)
115+
116+
return res

0 commit comments

Comments
 (0)