leetcode

Leetcode Solutions (0x6A73)
git clone https://git.pngu.org/leetcode
Log | Files | Refs | Submodules | README

commit 790ba8e85fa5957e4a23f18c5ceb546355423116
parent 6ae6a760d781bc31030db4fbf7b1a9de92a299a7
Author: Jack Sangdahl <jack@pngu.org>
Date:   Thu, 29 Jan 2026 21:09:46 -0700

2977. minimum cost to convert string 2

Diffstat:
Amin_cost_convert_str2.c | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amin_cost_convert_str2.py | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 219 insertions(+), 0 deletions(-)

diff --git a/min_cost_convert_str2.c b/min_cost_convert_str2.c @@ -0,0 +1,117 @@ +// 2977. Minimum Cost to Convert String II +#include "leetcode.h" + +/* + * you are given two 0 indexed strings 'source' and 'target'. both of length 'n' + * and consisting of lowercase english letters. you are also given two 0 indexed + * string arrays 'original' and 'changed', and an integer array 'cost' where + * 'cost[i]' represents the cost of converting the string 'original[i]' to the + * string 'changed[i]'. you start with the string 'source'. in one operation, + * you can pick a substring 'x' from the string and change it to 'y' at a cost + * of 'z' if there exists any index 'j' such that 'cost[j] == z', 'original[j] + * == x', and 'changed[j] == y'. you are allowed to do any number of operations + * but any pair of operations must satisfy either of these two conditions. + * return the minimum cost to convert the string 'source' to the string 'target' + * using any number of operations. if it is impossible to convert 'source' to + * 'target', return -1. note that there may exist indices 'i', 'j' such that + * 'original[i] == original[j]' and 'changed[i] == changed[j]' + */ + +struct trie { + struct trie *child[26]; + int id; +}; + +struct trie *trie_init(void) { + struct trie *node = (struct trie *)malloc(sizeof(struct trie)); + for (int i = 0; i < 26; i++) + node->child[i] = NULL; + node->id = -1; + return node; +} + +void trie_free(struct trie *node) { + if (node) + free(node); +} + +int trie_add(struct trie *node, const char *word, int *idx) { + for (int i = 0; word[i]; i++) { + int ch = word[i] - 'a'; + if (!node->child[ch]) + node->child[ch] = trie_init(); + node = node->child[ch]; + } + if (node->id == -1) + node->id = ++(*idx); + return node->id; +} + +void update(long long *x, long long y) { + if (*x == -1 || y < *x) + *x = y; +} + +long long minimumCost(char *source, char *target, char **original, + int originalSize, char **changed, int changedSize, + int *cost, int costSize) { + int n = strlen(source), m = originalSize, p = -1, node_cnt = m * 2; + int **grid = (int **)malloc(node_cnt * sizeof(int *)); + struct trie *root = trie_init(); + for (int i = 0; i < node_cnt; i++) { + grid[i] = (int *)malloc(node_cnt * sizeof(int)); + for (int j = 0; j < node_cnt; j++) + grid[i][j] = INT_MAX / 2; + grid[i][i] = 0; + } + for (int i = 0; i < m; i++) { + int x = trie_add(root, original[i], &p); + int y = trie_add(root, changed[i], &p); + grid[x][y] = fmin(grid[x][y], cost[i]); + } + for (int k = 0; k <= p; k++) + for (int i = 0; i <= p; i++) + for (int j = 0; j <= p; j++) + grid[i][j] = fmin(grid[i][j], grid[i][k] + grid[k][j]); + long long *f = (long long *)malloc(n * sizeof(long long)); + memset(f, -1, n * sizeof(long long)); + for (int j = 0; j < n; j++) { + if (j > 0 && f[j - 1] == -1) + continue; + long long base = !j ? 0 : f[j - 1]; + if (source[j] == target[j]) + update(&f[j], base); + struct trie *u = root, *v = root; + for (int i = j; i < n; i++) { + u = u->child[source[i] - 'a']; + v = v->child[target[i] - 'a']; + if (!u || !v) + break; + if (u->id != -1 && v->id != -1 && grid[u->id][v->id] != INT_MAX / 2) + update(&f[i], base + grid[u->id][v->id]); + } + } + long long ans = f[n - 1]; + for (int i = 0; i < node_cnt; i++) + free(grid[i]); + free(grid); + free(f); + trie_free(root); + return ans; +} + +int main() { + char *s1 = "abcd", *t1 = "acbe", *o1[] = {"a", "b", "c", "c", "e", "d"}, + *ch1[] = {"b", "c", "b", "e", "b", "e"}; + char *s2 = "abcdefgh", *t2 = "acdeeghh", *o2[] = {"bcd", "fgh", "thh"}, + *ch2[] = {"cde", "thh", "ghh"}; + char *s3 = "abcdefgh", *t3 = "addddddd", *o3[] = {"bcd", "defgh"}, + *ch3[] = {"ddd", "ddddd"}; + int co1[] = {2, 5, 5, 1, 2, 20}, co2[] = {1, 3, 5}, co3[] = {100, 1578}; + printf("%lld\n", minimumCost(s1, t1, o1, ARRAY_SIZE(o1), ch1, ARRAY_SIZE(ch1), + co1, ARRAY_SIZE(co1))); // expect: 28 + printf("%lld\n", minimumCost(s2, t2, o2, ARRAY_SIZE(o2), ch2, ARRAY_SIZE(ch2), + co2, ARRAY_SIZE(co2))); // expect: 9 + printf("%lld\n", minimumCost(s3, t3, o3, ARRAY_SIZE(o3), ch3, ARRAY_SIZE(ch3), + co3, ARRAY_SIZE(co3))); // expect: -1 +} diff --git a/min_cost_convert_str2.py b/min_cost_convert_str2.py @@ -0,0 +1,102 @@ +# 2977. Minimum Cost to Convert String II +import heapq +from collections import defaultdict + +""" +you are given two 0 indexed strings 'source' and 'target'. both of length 'n' +and consisting of lowercase english letters. you are also given two 0 indexed +string arrays 'original' and 'changed', and an integer array 'cost' where +'cost[i]' represents the cost of converting the string 'original[i]' to the +string 'changed[i]'. you start with the string 'source'. in one operation, +you can pick a substring 'x' from the string and change it to 'y' at a cost +of 'z' if there exists any index 'j' such that 'cost[j] == z', 'original[j] +== x', and 'changed[j] == y'. you are allowed to do any number of operations +but any pair of operations must satisfy either of these two conditions. +return the minimum cost to convert the string 'source' to the string 'target' +using any number of operations. if it is impossible to convert 'source' to +'target', return -1. note that there may exist indices 'i', 'j' such that +'original[i] == original[j]' and 'changed[i] == changed[j]' +""" + + +class Solution(object): + def minimumCost(self, source, target, original, changed, cost): + """ + :type source: str + :type target: str + :type original: List[str] + :type changed: List[str] + :type cost: List[int] + :rtype: int + """ + adj = defaultdict(lambda: defaultdict(int)) + change_lengths = set(len(sub) for sub in original) + for i, start in enumerate(original): + end = changed[i] + c = cost[i] + if end in adj[start]: + adj[start][end] = min(adj[start][end], c) + else: + adj[start][end] = c + + def dijkstra(start, end): + heap = [(0, start)] + costs = defaultdict(lambda: float("inf")) + costs[start] = 0 + while heap: + path_cost, curr = heapq.heappop(heap) + if curr == end: + return path_cost + for nei in adj[curr]: + nei_cost = adj[curr][nei] + new_cost = nei_cost + path_cost + if new_cost < costs[nei]: + costs[nei] = new_cost + heapq.heappush(heap, (new_cost, nei)) + return float("inf") + + def dfs(i): + if i >= len(target): + return 0 + c = float("inf") if target[i] != source[i] else dfs(i + 1) + for length in change_lengths: + t_sub = target[i : i + length] + s_sub = source[i : i + length] + trans_cost = dijkstra(s_sub, t_sub) + if trans_cost != float("inf"): + c = min(c, trans_cost + dfs(i + length)) + return c + + ans = dfs(0) + return ans if ans != float("inf") else -1 + + +if __name__ == "__main__": + obj = Solution() + print( + obj.minimumCost( + source="abcd", + target="acbe", + original=["a", "b", "c", "c", "e", "d"], + changed=["b", "c", "b", "e", "b", "e"], + cost=[2, 5, 5, 1, 2, 20], + ) + ) + print( + obj.minimumCost( + source="abcdefgh", + target="acdeeghh", + original=["bcd", "fgh", "thh"], + changed=["cde", "thh", "ghh"], + cost=[1, 3, 5], + ) + ) + print( + obj.minimumCost( + source="abcdefgh", + target="addddddd", + original=["bcd", "defgh"], + changed=["ddd", "ddddd"], + cost=[100, 1578], + ) + )