Leetcode 2977. Minimum Cost to Convert String II

  • Leetcode 2977. Minimum Cost to Convert String II
    • 1. 解题思路
    • 2. 代码实现
  • 题目链接:2977. Minimum Cost to Convert String II

1. 解题思路

这一题思路上和前一题差不多,还是先对给定的有向图求出其中任意两点间的最短距离,然后考察字符串的变换方式。

但是,这里相较于上一题的难度在于说,这里的有向图的变换节点不再单纯是字母了,因此组合更多了。

其次的话,由于变换的节点为不定长的字符串,因此对source字符串和target字符串的变换关系可以给出不同的拆分关系,可以有不同的cost,需要对其选择最小值。

但是,即便如此,思路上来说还是很直接的,上半部分本质上和上一题一模一样,用一个Floyd算法就能直接得到。

而关于后半部分,事实上更加简单,直接使用动态规划就行。

不过,实际在处理过程中,遇到了超时的问题,因此这里做了一些剪枝的优化操作,这部分还是比较零碎的:

  1. Floyd算法的算法复杂度是 O ( N 3 ) O(N^3) O(N3),因此我们需要对所有的节点进行一下去重,并且对第一层的节点提前求出了所有可能的中间节点的可能性,从而进一步进行了剪枝;
  2. 对于动态规划的部分,我们引入了一个trie树,使得遍历过程可以提前终止,将整体的算法复杂度从 O ( N 2 ) O(N^2) O(N2)大幅进行缩减。

但即便给出上述这些多少繁琐的剪枝操作,还是仅仅勉强通过了所有测试样例,耗时依然非常长,不知道其他大佬们是怎么处理的,看了一两个大佬们的解法,不过没有看懂就是了,唉……

2. 代码实现

给出python代码实现如下:

class Trie:
    def __init__(self):
        self.trie = {}
    
    def add_word(self, word):
        trie = self.trie
        for c in word:
            trie = trie.setdefault(c, {})
        trie["eos"] = ""

class Solution:
    def minimumCost(self, source: str, target: str, original: List[str], changed: List[str], cost: List[int]) -> int:
        n, m = len(source), len(original)
        
        costs = defaultdict(lambda: math.inf)
        for src, tgt, c in zip(original, changed, cost):
            costs[(src, tgt)] = min(c, costs[(src, tgt)])
        original = list(set(original))
        changed_set = set(changed)
        changed = list(changed_set)
        interval = [src for src in original if src in changed_set]
        for mid in interval:
            for src in original:
                for tgt in changed:
                    costs[(src, tgt)] = min(costs[(src, tgt)], costs[(src, mid)] + costs[(mid, tgt)])
        
        trie = Trie()
        for src in original:
            trie.add_word(src)

        @lru_cache(None)
        def dp(idx):
            if idx >= n:
                return 0
            ans = math.inf
            _trie = trie.trie
            src, tgt = "", ""
            for j in range(idx, n):
                src, tgt = src + source[j], tgt + target[j]
                if src == tgt:
                    ans = min(ans, dp(j+1))
                elif (src, tgt) in costs:
                    ans = min(ans, costs[(src, tgt)] + dp(j+1))
                if source[j] not in _trie:
                    break
                _trie = _trie[source[j]]
            return ans
        
        ans = dp(0)
        return ans if ans != math.inf else -1

提交代码评测得到:耗时16432ms,占用内存30.3MB。

你可能感兴趣的:(leetcode笔记,leetcode,2977,leetcode,hard,leetcode周赛377,Floyd算法,动态规划)