이 문제는 문자열 s에서 문자열 t를 **부분 수열(subsequence)**로 만들 수 있는 서로 다른 방법의 수를 구하는 문제입니다.
S의 부분 수열 = 문자열 T를 만드는 수 찾는 것
이를 해결하기 위해 **동적 계획법(DP)**을 사용합니다.
문제 이해
- 부분 수열 (Subsequence):
- 문자열의 일부 문자들을 선택해 순서를 유지하면서 생성된 새로운 문자열.
- 예: s="rabbbit", t="rabbit"
- 부분 수열로 t를 생성하는 방법:
- 첫 번째 r, 첫 번째 a, 첫 번째 b, 두 번째 b, 첫 번째 i, 첫 번째 t.
- ...
- 총 3가지 방법.
- 부분 수열로 t를 생성하는 방법:
- 목표:
- s에서 t를 생성하는 모든 부분 수열의 개수를 반환.
시간 및 공간 복잡도
- 시간 복잡도:
- O(m×n): DP 테이블 크기에 비례.
- 공간 복잡도:
- O(m×n): DP 테이블 사용.
예제
class Solution:
def numDistinct(self, s: str, t: str) -> int:
cache = {} # 캐싱을 위한 딕셔너리 / Cache dictionary for memoization
def dfs(i, j):
# t의 모든 문자를 찾았으면 1을 반환
# If all characters in t are matched, return 1
if j == len(t):
return 1
# s가 끝났는데 t를 완성하지 못한 경우 0을 반환
# If s is fully traversed but t is not matched, return 0
if i == len(s):
return 0
# 캐시가 존재하면 캐시값 반환
# If the result for (i, j) is already computed, return it
if (i, j) in cache:
return cache[(i, j)]
# 두 문자가 같으면 두 가지 선택을 고려
# If the characters match, consider two choices:
if s[i] == t[j]:
# (1) 매칭하여 진행 / Match and move forward
# (2) 건너뛰고 진행 / Skip the character in s and move forward
cache[(i, j)] = dfs(i + 1, j + 1) + dfs(i + 1, j)
else:
# 두 문자가 다르면 s[i]를 건너뜀
# If the characters don't match, skip s[i]
cache[(i, j)] = dfs(i + 1, j)
# 결과를 캐시에 저장하고 반환
# Save the result in the cache and return it
return cache[(i, j)]
# dfs 함수 시작
# Start the recursive DFS from the beginning of both strings
return dfs(0, 0)
'LeetCode > DP심화' 카테고리의 다른 글
646. Maximum Length of Pair Chain (0) | 2025.01.05 |
---|---|
673. Number of Longest Increasing Subsequence ★★★ (0) | 2025.01.05 |
712. Minimum ASCII Delete Sum for Two Strings ★★ (0) | 2025.01.04 |
516. Longest Palindromic Subsequence ★★ (0) | 2025.01.04 |
931. Minimum Falling Path Sum (0) | 2025.01.03 |