diff --git a/longest-common-subsequence/taurus09318976.py b/longest-common-subsequence/taurus09318976.py new file mode 100644 index 000000000..11cf25c87 --- /dev/null +++ b/longest-common-subsequence/taurus09318976.py @@ -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] + + diff --git a/palindromic-substrings/taurus09318976.py b/palindromic-substrings/taurus09318976.py new file mode 100644 index 000000000..f676e67e7 --- /dev/null +++ b/palindromic-substrings/taurus09318976.py @@ -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 # 이 중심에서 찾은 총 회문 개수 반환 + + +