Skip to content

[taurus09318976] WEEK 08 Solutions #1515

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions longest-common-subsequence/taurus09318976.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
'''
문제 핵심 : 이 문제는 두 문자열에서 가장 긴 공통 부분수열의 길이를 찾는 것임
여기서 부분수열이란, 원래 문자열에서 일부 문자를 삭제해도 되지만, 남은 문자들의 순서는 바뀌면 안되는 새로운 문자열임

해결방법 : 1) 2차원 표를 만들어서 각 위치에 "여기까지의 최대 공통 부분수열 길이"를 저장함
2) 두 문자가 같으면, 이전 결과에 1을 더함
3) 두 문자가 다르면, 위쪽 또는 왼쪽 중 더 큰 값을 가져옴

시간 복잡도: O(m × n)
외부 반복문이 m번 실행됨 (text1의 길이)
내부 반복문이 n번 실행됨 (text2의 길이)
각 반복에서 하는 작업은 상수 시간 O(1)임
따라서 총 시간 복잡도는 O(m × n)임

공간 복잡도: O(m × n)
(m+1) × (n+1) 크기의 2차원 배열 dp를 사용함
따라서 공간 복잡도는 O(m × n)입니다

'''

class Solution:
def longestCommonSubsequence(self, text1: str, text2: str):
m = len(text1) # 첫 번째 문자열의 길이를 m에 저장
n = len(text2) # 두 번째 문자열의 길이를 n에 저장

# (m+1) x (n+1) 크기의 2차원 리스트를 만들고 모든 값을 0으로 초기화
# +1을 하는 이유: 빈 문자열과의 비교를 위해 첫 번째 행과 열을 0으로 둠
dp = [[0] * (n + 1) for k in range(m + 1)]

# 1부터 시작하는 이유: 0번째 행과 열은 빈 문자열을 의미하므로 이미 0으로 초기화됨
for i in range(1, m + 1): # text1의 각 문자에 대해
for j in range(1, n + 1): # text2의 각 문자에 대해
# text1의 (i-1)번째 문자와 text2의 (j-1)번째 문자가 같은지 확인
# i-1, j-1을 사용하는 이유: dp 배열은 1부터 시작하지만 문자열 인덱스는 0부터 시작
if text1[i-1] == text2[j-1]:
# 같으면: 대각선 위 값에 1을 더함 (이전까지의 가장 긴 공통 부분수열 + 현재 일치하는 문자 1개)
dp[i][j] = dp[i-1][j-1] + 1
else:
# 다르면: 위쪽 값과 왼쪽 값 중 더 큰 값을 선택
# 위쪽: text1에서 현재 문자를 제외한 경우
# 왼쪽: text2에서 현재 문자를 제외한 경우
dp[i][j] = max(dp[i-1][j], dp[i][j-1])

# dp[m][n]에는 전체 문자열에 대한 가장 긴 공통 부분수열 길이가 저장됨
return dp[m][n]


43 changes: 43 additions & 0 deletions palindromic-substrings/taurus09318976.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
'''
문제핵심 : palindrome인 부분 문자열의 개수를 세는 것임
해결방법 :
1) 문자열의 각 위치를 palindrome 중심으로 생각함
2) 중심에서 양쪽으로 확장하면서 palindrome 인지 확인
3) 홀수 길이 palindrome (중심이 한 글자)과 짝수 길이 palindrome (중심이 두 글자 사이) 모두 확인

시간 복잡도: O(n²)
외부 반복문이 n번 실행됨 (n은 문자열 길이)
각 중심에서 최악의 경우 n번까지 확장할 수 있음
따라서 총 시간 복잡도는 O(n × n) = O(n²)임

공간 복잡도: O(1)
추가로 사용하는 메모리는 몇 개의 변수(count, left, right, palindrome_count)뿐임
입력 크기에 관계없이 일정한 메모리만 사용하므로 O(1)임
'''

class Solution:
def countSubstrings(self, s: str):
count = 0 # 전체 회문 개수를 저장할 변수를 0으로 초기화

for i in range(len(s)): # 문자열의 각 인덱스를 순회
# i번째 문자를 중심으로 하는 홀수 길이 회문들을 찾아서 개수를 더함
count += self.expandAroundCenter(s, i, i)
# i와 i+1 사이를 중심으로 하는 짝수 길이 회문들을 찾아서 개수를 더함
count += self.expandAroundCenter(s, i, i + 1)

return count # 총 회문 개수 반환

def expandAroundCenter(self, s: str, left: int, right: int) -> int:
palindrome_count = 0 # 이 중심에서 찾은 회문 개수를 0으로 초기화

# 조건: 왼쪽 인덱스가 0 이상이고, 오른쪽 인덱스가 문자열 길이 미만이고,
# 왼쪽과 오른쪽 문자가 같을 때
while left >= 0 and right < len(s) and s[left] == s[right]:
palindrome_count += 1 # 회문을 하나 찾았으므로 개수 증가
left -= 1 # 다음 확장을 위해 왼쪽 인덱스를 1 감소
right += 1 # 다음 확장을 위해 오른쪽 인덱스를 1 증가

return palindrome_count # 이 중심에서 찾은 총 회문 개수 반환