LeetCode/DP심화

72. Edit Distance

hyunkookim 2024. 11. 8. 17:44

72. Edit Distance

 

https://youtu.be/XYi2-LPrwm4?si=8R5kcaUc9tWO8sSQ

 

 

 

 

 

초기값 세팅 설명

초기 설정의 의미

  • 첫 번째 행과 열은 문자열이 비어 있을 때 작업의 기준점을 제공합니다.
  • 이후, 이 값을 기반으로 나머지 테이블 값을 채우며 두 문자열의 변환 비용을 계산합니다.

이후 과정

결론

DP 테이블의 최종 값은 문자열을 변환하는 모든 가능한 경로를 고려해 최적의 변환 비용을 계산한 결과입니다. 이를 통해 삽입, 삭제, 교체 작업을 효율적으로 비교할 수 있습니다.

 

Code

class Solution:
    def minDistance(self, word1: str, word2: str) -> int:
        # DP 테이블 생성
        # cache[i][j]: word1[i:]를 word2[j:]로 변환하는 최소 작업 수
        cache = [[float("inf")] * (len(word2) + 1) for i in range(len(word1) + 1)]
        
        # 초기값 설정
        # word1이 비어 있는 경우: word2[j:]로 변환하기 위해 삽입만 필요
        for j in range(len(word2) + 1):
            cache[len(word1)][j] = len(word2) - j  # 남은 글자 수만큼 삽입

        # word2가 비어 있는 경우: word1[i:]를 비우기 위해 삭제만 필요
        for i in range(len(word1) + 1):
            cache[i][len(word2)] = len(word1) - i  # 남은 글자 수만큼 삭제

        # DP 테이블 계산
        # 역순으로 계산: word1[i:]와 word2[j:]를 고려
        for i in range(len(word1) - 1, -1, -1):  # word1의 끝에서 시작
            for j in range(len(word2) - 1, -1, -1):  # word2의 끝에서 시작
                if word1[i] == word2[j]:  # 두 문자가 같으면 작업 필요 없음
                    cache[i][j] = cache[i + 1][j + 1]
                else:  # 삽입, 삭제, 교체 중 최소 작업 선택
                    cache[i][j] = 1 + min(
                        cache[i + 1][j],     # 삭제: word1[i] 삭제
                        cache[i][j + 1],     # 삽입: word2[j] 삽입
                        cache[i + 1][j + 1]  # 교체: word1[i]를 word2[j]로 교체
                    )

        # 최종 결과: word1[0:]를 word2[0:]로 변환하는 최소 작업 수
        return cache[0][0]

# 예제 실행
solution = Solution()
print(solution.minDistance("horse", "ros"))  # 출력: 3
print(solution.minDistance("intention", "execution"))  # 출력: 5

 

아래 코드로..

 

https://youtu.be/dY_dZohgVa8?si=DGLuMiDNJzl1cj1P

 

class Solution:
    def minDistance(self, word1: str, word2: str) -> int:        
        len1 = len(word1)
        len2 = len(word2)

        # 배열 만들기
        # 결국 답은 dp[len1][len2]
        """
        i 는 1부터 len1 = len(word1) 까지
        j 는 1부터 len2 = len(word2) 까지

        d[i][j]
            word1 의 i 까지의 부분 문자열을  
            word2 의 j 까지의 부분 문자열로 
            교체하기 위한 최소 작업 수

        문자열이 abs -> def 로 주어질때
            d[1][1] 은
            a->d, 즉, a 를 d로 바꾸기 위한 최소 작업수: 1        
        """

        # 배열 생성, +1 꼭 필요
        # 배열 생성시, len1, len2 순서 중요!
        # dp = ([0]*(len2+1)) *(len1+1) <- 이건 2차원 배열 아님
        dp = [[0] * (len2 + 1) for _ in range(len1 + 1)]

        # 초기화
        # i: word1 의 부분 문자열 이고
        # j: 0  즉, "" 공백 문자열. 이었을때
        # 첫번째 문자열을 공백으로 교체하기 위한 최소 작업수
        # 첫번째 문자열의 단어 길이만큼 필요
        # word1 = "horse" 이면
        # dp[1][0] 은 'h' 와 공백 -> 1글자를 공백으로 -> 작업수 1번 필요
        # dp[2][0] 은 'ho' 와 공백 -> 2글자를 공백으로 -> 작업수 2번 필요
        # dp[3][0] 은 'hor' 와 공백 -> 3글자를 공백으로 -> 작업수 3번 필요
        # .. 이런식
        for i in range(len1 + 1): # 초기화는 +1 꼭 필요
            dp[i][0] = i

        # j: word2 의 부분 문자열
        for j in range(len2 + 1):
            dp[0][j] = j

        # 루프: 1부터 ~ *주의*
        for i in range(1, len1+1): 
            for j in range(1, len2+1):                
                if word1[i-1] == word2[j-1]: 
                    # word1의 i번째 문자와 word2의 j번째 문자가 같으면, 
                    # 메모이제이션 배열에서 대각선 위의 값을 가져오면 됨
                    # 왜냐면, 문자가 같기때문에, 어떤 오퍼레이션이 추가로 필요없음
                    # 그래서, 그 전의 i-1, j-1의 값이 그대로 i,j 값이 됨
                    dp[i][j] = dp[i-1][j-1]
                else:
                    # 문자가 다르면
                    # 추가 작업인
                    # insert, delete, replace 중 하나가 필요하니, 작업이 1 더 더해짐
                    dp[i][j] = min(dp[i-1][j-1], dp[i][j-1], dp[i-1][j]) + 1

        # 리턴: 마지막..값으로.. *주의*
        return dp[len1][len2]

 

 

 

https://youtu.be/6jvSfC2-JDo?si=R2jXQFFVxaokuPBW

 

 

class Solution:
    def minDistance(self, word1: str, word2: str) -> int:
        M, N = len(word1), len(word2)

        dp = [[0] * (N+1) for _ in range(M+1)] # +1 주의
        for m in range(M+1): # +1 주의
            dp[m][0] = m
        for n in range(N+1): # +1 주의 
            dp[0][n] = n

        for m in range(1, M+1): # 1부터 주의
            for n in range(1, N+1): # 1부터 주의
                """
                문자열의 실제 인덱스는 0부터 시작하지만, 
                DP 테이블은 1부터 시작하도록 설정됨
                따라서, dp[m][n]은 문자열의 실제 인덱스 m−1과 n−1을 참조함
                """
                if word1[m-1] == word2[n-1]: # 왜 -1??
                    dp[m][n] = dp[m-1][n-1]
                else:
                    dp[m][n] = min(dp[m-1][n-1], dp[m][n-1], dp[m-1][n]) + 1
        return dp[M][N]

 

'LeetCode > DP심화' 카테고리의 다른 글

322. Coin Change  (0) 2024.12.29
139. Word Break ★  (0) 2024.12.29
746. Min Cost Climbing Stairs ★  (0) 2024.11.23
1137. N-th Tribonacci Number  (1) 2024.11.22
714. Best Time to Buy and Sell Stock with Transaction Fee  (2) 2024.11.08