LC 2977. 转换字符串的最小成本 II

https://leetcode.cn/problems/minimum-cost-to-convert-string-ii/

这题也有一个简单的版本,但是这题简单版本转换是单字符,可以对单字符进行更改,相对就简单多了。这题是可以针对字符串进行更改,但是存在两个限制,就是修改的部分不能重合,就让这个问题简单了不少。并且 \(source.length == target.length <= 1000\), 所以这题可以使用O(n^2) 的dp算法来计算。

这题在实现的时候有两个注意点:

class Solution:
    def minimumCost(self, source: str, target: str, original: List[str], changed: List[str], cost: List[int]) -> int:
        dictIndex = {}
        dictData = []
        for s in original + changed:
            if s not in dictIndex:
                dictIndex[s] = len(dictData)
                dictData.append(s)

        INF = 1 << 63
        n = len(dictData)
        C = [[INF] * n for _ in range(n)]
        for i in range(len(original)):
            a, b, c = original[i], changed[i], cost[i]
            a, b = dictIndex[a], dictIndex[b]
            C[a][b] = min(C[a][b], c)

        for t in range(n):
            opts = []
            for i in range(n):
                if len(dictData[i]) == len(dictData[t]):
                    opts.append(i)
            for i in opts:
                for j in opts:
                    C[i][j] = min(C[i][j], C[i][t] + C[t][j])

        class Trie:
            def __init__(self):
                self.child = [None] * 26
                self.index = -1

            def insert(self, s, index):
                t = self
                for c in s:
                    d = ord(c) - ord('a')
                    if not t.child[d]:
                        t2 = Trie()
                        t.child[d] = t2
                    t = t.child[d]
                t.index = index

            def move(self, c):
                d = ord(c) - ord('a')
                return self.child[d]

        root = Trie()
        for i in range(len(dictData)):
            s = dictData[i]
            root.insert(s, i)

        N = len(source)
        dp = [0] * (N + 1)
        for i in reversed(range(N)):
            same = True
            r = INF
            a, b = root, root
            for j in range(i, N):
                same = same & (source[j] == target[j])
                if a and b:
                    a, b = a.move(source[j]), b.move(target[j])

                if same:
                    r = min(r, dp[j + 1])
                elif not (a and b):
                    break
                elif a.index != -1 and b.index != -1:
                    ta, tb = a.index, b.index
                    c = C[ta][tb]
                    r = min(r, c + dp[j + 1])
            dp[i] = r

        if dp[0] == INF:
            return -1
        return dp[0]