Minimum Cost to Convert String II solution and explanation
9 more videos on this problem
Minimum Cost to Convert String II | Simplified Explanation | Intuition | Leetcode 2977 | MIKcodestorywithMIK · 49:43 · 8K views
Minimum Cost to Convert String II | LeetCode 2977 | DP on Substrings | No Trie NeededSanyam IIT Guwahati · 41:06 · 1K views
Minimum Cost to Convert String II | LeetCode 2977 | Trie + DP + Optimization Explained Study Placement · 1:13:18 · 752 views
2977. Minimum Cost to Convert String II (Leetcode Hard)Programming Live with Larry · 37:41 · 616 views
Minimum Cost to Convert String II | LeetCode 2977 - Pythonimpoldev · 16:32 · 541 views
Daily Leetcode #2131: Jan 30, 2026 - 2977. Minimum Cost to Convert String IIProgramming Live with Larry · 1:03:56 · 484 views
2977. Minimum Cost to Convert String II | Leetcode Daily - PythonLeetcode Daily · 10:05 · 482 views
Minimum Cost to Convert String II - LeetCode 2977 - PythonAlpha-Code · 19:42 · 248 views
Minimum Cost to Convert String II | LeetCode 2977 | Graph | Dynamic Programming | Floyd WarshallcodeTips · 36:57 · 217 views
Minimum Cost to Convert String II Leetcode 2977 | Java-HindiKernel Queen 👑 · 23:56 · 186 views
The problem
You are given two 0-indexed strings source and target, both of length n and consisting of lowercase English characters. 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:
- The substrings picked in the operations are
source[a..b]andsource[c..d]with eitherb < cord < a. In other words, the indices picked in both operations are disjoint. - The substrings picked in the operations are
source[a..b]andsource[c..d]witha == candb == d. In other words, the indices picked in both operations are identical.
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[j] == original[i] and changed[j] == changed[i].
Example 1:
Input: 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] Output: 28 Explanation: To convert "abcd" to "acbe", do the following operations: - Change substring source[1..1] from "b" to "c" at a cost of 5. - Change substring source[2..2] from "c" to "e" at a cost of 1. - Change substring source[2..2] from "e" to "b" at a cost of 2. - Change substring source[3..3] from "d" to "e" at a cost of 20. The total cost incurred is 5 + 1 + 2 + 20 = 28. It can be shown that this is the minimum possible cost.
Example 2:
Input: source = "abcdefgh", target = "acdeeghh", original = ["bcd","fgh","thh"], changed = ["cde","thh","ghh"], cost = [1,3,5] Output: 9 Explanation: To convert "abcdefgh" to "acdeeghh", do the following operations: - Change substring source[1..3] from "bcd" to "cde" at a cost of 1. - Change substring source[5..7] from "fgh" to "thh" at a cost of 3. We can do this operation because indices [5,7] are disjoint with indices picked in the first operation. - Change substring source[5..7] from "thh" to "ghh" at a cost of 5. We can do this operation because indices [5,7] are disjoint with indices picked in the first operation, and identical with indices picked in the second operation. The total cost incurred is 1 + 3 + 5 = 9. It can be shown that this is the minimum possible cost.
Example 3:
Input: source = "abcdefgh", target = "addddddd", original = ["bcd","defgh"], changed = ["ddd","ddddd"], cost = [100,1578] Output: -1 Explanation: It is impossible to convert "abcdefgh" to "addddddd". If you select substring source[1..3] as the first operation to change "abcdefgh" to "adddefgh", you cannot select substring source[3..7] as the second operation because it has a common index, 3, with the first operation. If you select substring source[3..7] as the first operation to change "abcdefgh" to "abcddddd", you cannot select substring source[1..3] as the second operation because it has a common index, 3, with the first operation.
Constraints:
1 <= source.length == target.length <= 1000source,targetconsist only of lowercase English characters.1 <= cost.length == original.length == changed.length <= 1001 <= original[i].length == changed[i].length <= source.lengthoriginal[i],changed[i]consist only of lowercase English characters.original[i] != changed[i]1 <= cost[i] <= 106
Approach overview
Problem Overview: You receive two strings source and target plus a list of substring conversions where original[i] can be turned into changed[i] with a cost. Conversions can be chained, and you must transform source into target with the minimum total cost.
Approach 1: Dynamic Programming + Trie + Shortest Path (Time: O(n·L + k^3), Space: O(k^2 + n))
The key challenge is that substring conversions can chain together, meaning converting a → b → c might be cheaper than a direct rule. First treat each unique pattern from original and changed as a node in a graph. Build edges from original[i] to changed[i] with weight cost[i], then run an all‑pairs shortest path algorithm such as Floyd–Warshall to compute the minimum conversion cost between every pair of patterns. Next, store the patterns in a Trie so you can quickly match substrings while scanning the strings. Use dynamic programming where dp[i] represents the minimum cost to convert the first i characters. From each position i, walk both the source and target through the Trie simultaneously to find valid substring pairs and update dp[j]. This combines Dynamic Programming, Trie, and Shortest Path techniques to efficiently evaluate all valid conversions.
Approach 2: DFS with Memoization (Time: O(n·L + states), Space: O(n + recursion))
A top‑down variant treats the problem as a recursive search over the string index. Starting at position i, try every substring conversion that matches the current prefix of source and the corresponding part of target. For each valid segment, recursively compute the cost of converting the remaining suffix. Memoize results for each index so the same suffix is never recomputed. As with the DP approach, shortest conversion costs between patterns must be precomputed using a graph algorithm. This version is often easier to implement in Python but can be slightly slower due to recursion overhead and repeated substring checks.
Recommended for interviews: The bottom‑up dynamic programming approach with Trie matching and precomputed shortest paths is the most robust solution. Interviewers want to see that you model substring transformations as a graph problem and combine it with DP over string positions. Explaining the brute reasoning (trying every substring) shows understanding, while optimizing with Trie lookups and shortest path preprocessing demonstrates strong algorithmic design.
Approach 1: Approach 1: Dynamic Programming
In this approach, we use dynamic programming to solve the problem. We create a DP table where dp[i] represents the minimum cost to transform source[0..i] to target[0..i].
Iterate over each position and evaluate possible transformations using the given substring transformations. If a valid transformation is found that respects the condition, update the DP table with the transformation cost.
The result will be the minimum cost to transform the entire source to target, stored in dp[n-1]. If no valid transformations can achieve this, return -1.
def minCostToConvert(source, target, original, changed, cost):
n = len(source)
m = len(original)
dp = [float('inf')] * (n + 1)
dp[0] = 0
for i in range(n):
if dp[i] == float('inf'):
continue
for j in range(m):
len_sub = len(original[j])
if i + len_sub <= n and source[i:i+len_sub] == original[j]:
new_section = changed[j]
if target[i:i+len_sub] == new_section:
dp[i + len_sub] = min(dp[i + len_sub], dp[i] + cost[j])
return dp[n] if dp[n] != float('inf') else -1
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(minCostToConvert(source, target, original, changed, cost))import java.util.*;
public class MinCostConversion {
public static int minCostToConvert(String source, String target, String[] original, String[] changed, int[] cost) {
int n = source.length();
int m = original.length;
int[] dp = new int[n + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = 0;
for (int i = 0; i < n; ++i) {
if (dp[i] == Integer.MAX_VALUE) continue;
for (int j = 0; j < m; ++j) {
int len = original[j].length();
if (i + len <= n && source.substring(i, i + len).equals(original[j])) {
String newSection = changed[j];
boolean transformationPossible = target.contains(original[j]);
if (transformationPossible && target.substring(i, i + len).equals(newSection)) {
dp[i + len] = Math.min(dp[i + len], dp[i] + cost[j]);
}
}
}
}
return dp[n] == Integer.MAX_VALUE ? -1 : dp[n];
}
public static void main(String[] args) {
String source = "abcd";
String target = "acbe";
String[] original = {"a", "b", "c", "c", "e", "d"};
String[] changed = {"b", "c", "b", "e", "b", "e"};
int[] cost = {2, 5, 5, 1, 2, 20};
int result = minCostToConvert(source, target, original, changed, cost);
System.out.println(result);
}
}#include <iostream>
#include <vector>
#include <string>
#include <climits>
using namespace std;
int minCostToConvert(string source, string target, vector<string>& original, vector<string>& changed, vector<int>& cost) {
int n = source.size();
vector<int> dp(n + 1, INT_MAX);
dp[0] = 0;
for (int i = 0; i < n; ++i) {
if (dp[i] == INT_MAX)
continue;
for (int j = 0; j < original.size(); ++j) {
int len = original[j].size();
if (i + len <= n && source.substr(i, len) == original[j]) {
string newSection = changed[j];
bool transformationPossible = (target.find(original[j]) != string::npos);
if (transformationPossible && target.substr(i, len) == newSection) {
dp[i + len] = min(dp[i + len], dp[i] + cost[j]);
}
}
}
}
return dp[n] == INT_MAX ? -1 : dp[n];
}
int main() {
string source = "abcd";
string target = "acbe";
vector<string> original = {"a","b","c","c","e","d"};
vector<string> changed = {"b","c","b","e","b","e"};
vector<int> cost = {2,5,5,1,2,20};
int result = minCostToConvert(source, target, original, changed, cost);
cout << result << endl;
return 0;
}function minCostToConvert(source, target, original, changed, cost) {
let n = source.length;
let dp = new Array(n + 1).fill(Infinity);
dp[0] = 0;
for (let i = 0; i < n; ++i) {
if (dp[i] === Infinity) continue;
for (let j = 0; j < original.length; ++j) {
let len = original[j].length;
if (i + len <= n && source.substring(i, i + len) === original[j]) {
let newSection = changed[j];
if (target.substring(i, i + len) === newSection) {
dp[i + len] = Math.min(dp[i + len], dp[i] + cost[j]);
}
}
}
}
return dp[n] === Infinity ? -1 : dp[n];
}
let source = "abcd";
let target = "acbe";
let original = ["a", "b", "c", "c", "e", "d"];
let changed = ["b", "c", "b", "e", "b", "e"];
let cost = [2, 5, 5, 1, 2, 20];
console.log(minCostToConvert(source, target, original, changed, cost));#include <stdio.h>
#include <string.h>
#include <limits.h>
int minCostToConvert(char* source, char* target, char** original, char** changed, int* cost, int n, int m) {
int dp[n+1];
for (int i = 0; i <= n; i++)
dp[i] = INT_MAX;
dp[0] = 0;
for (int i = 0; i < n; i++) {
if (dp[i] == INT_MAX) continue;
for (int j = 0; j < m; j++) {
int len = strlen(original[j]);
if (i + len <= n && strncmp(&source[i], original[j], len) == 0) {
char newSection[101];
strncpy(newSection, &source[i], len);
newSection[len] = '\0';
int transformationPossible = !!strstr(target, newSection);
if (transformationPossible) {
strncpy(newSection, changed[j], len);
newSection[len] = '\0';
if (strncmp(&target[i], newSection, len) == 0)
dp[i + len] = dp[i + len] < dp[i] + cost[j] ? dp[i + len] : dp[i] + cost[j];
}
}
}
}
return dp[n] == INT_MAX ? -1 : dp[n];
}
int main() {
char* source = "abcd";
char* target = "acbe";
char* original[] = {"a","b","c","c","e","d"};
char* changed[] = {"b","c","b","e","b","e"};
int cost[] = {2,5,5,1,2,20};
int n = strlen(source);
int m = 6;
int result = minCostToConvert(source, target, original, changed, cost, n, m);
printf("%d\n", result);
return 0;
}using System;
class Program {
public static int MinCostToConvert(string source, string target, string[] original, string[] changed, int[] cost) {
int n = source.Length;
int[] dp = new int[n + 1];
Array.Fill(dp, int.MaxValue);
dp[0] = 0;
for (int i = 0; i < n; ++i) {
if (dp[i] == int.MaxValue) continue;
for (int j = 0; j < original.Length; ++j) {
int len = original[j].Length;
if (i + len <= n && source.Substring(i, len) == original[j]) {
string newSection = changed[j];
if (target.Substring(i, len) == newSection) {
dp[i + len] = Math.Min(dp[i + len], dp[i] + cost[j]);
}
}
}
}
return dp[n] == int.MaxValue ? -1 : dp[n];
}
public static void Main() {
string source = "abcd";
string target = "acbe";
string[] original = {"a","b","c","c","e","d"};
string[] changed = {"b","c","b","e","b","e"};
int[] cost = {2,5,5,1,2,20};
var result = MinCostToConvert(source, target, original, changed, cost);
Console.WriteLine(result);
}
}Python's implementation leverages a DP list to iteratively attempt transformations on the source matching segments in the target. The solution iterates over the lengths of substrings and checks replacement feasibility and costs.
Time Complexity: O(n * m * l), where l is the length of each substring (original[i]). Space Complexity: O(n).
Approach 2: Approach 2: DFS with Memoization
Use a depth-first search (DFS) approach combined with memoization to explore all possible substring transformations. Start by exploring possible transformations from the beginning of the string, keeping a record of costs incurred so far.
At each step, attempt to match the start of source with each possible original transformation and recur for the remaining part of the string. Use memoization to store results of previously computed subproblems to reduce redundant calculations.
The result will be the minimum cost obtained from all valid transformation paths. Return -1 if a valid transformation path to target doesn't exist.
def minCostToConvertDFS(source, target, original, changed, cost):
memo = {}
m = len(source)
def dfs(idx):
if idx >= m:
return 0
if idx in memo:
return memo[idx]
min_cost = float('inf')
for j in range(len(original)):
len_sub = len(original[j])
if idx + len_sub <= m and source[idx:idx+len_sub] == original[j]:
new_section = changed[j]
if target[idx:idx+len_sub] == new_section:
total_cost = dfs(idx + len_sub)
if total_cost != float('inf'):
min_cost = min(min_cost, cost[j] + total_cost)
memo[idx] = min_cost
return min_cost
result = dfs(0)
return -1 if result == float('inf') else result
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(minCostToConvertDFS(source, target, original, changed, cost))This Python solution uses DFS with memoization to explore substring transformation paths, tracking minimal costs recursively. It caches results of previously traversed paths to avoid redundant computations, ensuring efficiency.
Time Complexity: Approximately O(n * m), which is less than the full combinatorial exploration due to memoization. Space Complexity: O(n) for storing results of recursion and memoization cache.
Approach 3: Trie + Floyd Algorithm + Memoization Search
According to the problem description, we can consider each string as a node, and the conversion cost between each pair of strings as a directed edge. We first initialize a 26 times 26 two-dimensional array g, where g[i][j] represents the minimum cost of converting string i to string j. Initially, g[i][j] = infty, and if i = j, then g[i][j] = 0. Here, we can use a trie to store the strings in original and changed along with their corresponding integer identifiers.
Next, we use the Floyd algorithm to calculate the minimum cost between any two strings.
Then, we define a function dfs(i) to represent the minimum cost of converting the string source[i..] to the string target[i..]. The answer is dfs(0).
The calculation process of the function dfs(i) is as follows:
- If
i geq |source|, no conversion is needed, return0. - Otherwise, if
source[i] = target[i], we can skip directly and recursively calculatedfs(i + 1). We can also enumerate the indexjin the range[i, |source|), ifsource[i..j]andtarget[i..j]are both in the trie, and their corresponding integer identifiersxandyare both greater than or equal to0, then we can adddfs(j + 1)andg[x][y]to get the cost of one conversion scheme, and we take the minimum value among all schemes.
In summary, we can get:
$
dfs(i) = \begin{cases}
0, & i geq |source| \
dfs(i + 1), & source[i] = target[i] \
min_{i leq j < |source|} { dfs(j + 1) + g[x][y] }, & otherwise
\end{cases}
Where x and y are the integer identifiers of source[i..j] and target[i..j] in the trie, respectively.
To avoid repeated calculations, we can use memoization search.
The time complexity is O(m^3 + n^2 + m times n), and the space complexity is O(m^2 + m times n + n). Where m and n$ are the lengths of the arrays original and source, respectively.
class Node {
children: (Node | null)[] = Array(26).fill(null);
v: number = -1;
}
function minimumCost(
source: string,
target: string,
original: string[],
changed: string[],
cost: number[],
): number {
const m = cost.length;
const n = source.length;
const g: number[][] = Array.from({ length: m << 1 }, () => Array(m << 1).fill(Infinity));
const root: Node = new Node();
let idx: number = 0;
const f: number[] = Array(n).fill(-1);
const insert = (w: string): number => {
let node: Node = root;
for (const c of w) {
const i: number = c.charCodeAt(0) - 'a'.charCodeAt(0);
if (node.children[i] === null) {
node.children[i] = new Node();
}
node = node.children[i] as Node;
}
if (node.v < 0) {
node.v = idx++;
}
return node.v;
};
const dfs = (i: number): number => {
if (i >= n) {
return 0;
}
if (f[i] !== -1) {
return f[i];
}
let res: number = source[i] === target[i] ? dfs(i + 1) : Infinity;
let p: Node = root;
let q: Node = root;
for (let j = i; j < source.length; ++j) {
p = p.children[source[j].charCodeAt(0) - 'a'.charCodeAt(0)] as Node;
q = q.children[target[j].charCodeAt(0) - 'a'.charCodeAt(0)] as Node;
if (p === null || q === null) {
break;
}
if (p.v < 0 || q.v < 0) {
continue;
}
const t: number = g[p.v][q.v];
res = Math.min(res, t + dfs(j + 1));
}
return (f[i] = res);
};
for (let i = 0; i < m; ++i) {
const x: number = insert(original[i]);
const y: number = insert(changed[i]);
g[x][y] = Math.min(g[x][y], cost[i]);
}
for (let k = 0; k < idx; ++k) {
for (let i = 0; i < idx; ++i) {
if (g[i][k] >= Infinity) {
continue;
}
for (let j = 0; j < idx; ++j) {
g[i][j] = Math.min(g[i][j], g[i][k] + g[k][j]);
}
}
}
const ans: number = dfs(0);
return ans >= Infinity ? -1 : ans;
}type Node struct {
children [26]*Node
v int
}
func newNode() *Node {
return &Node{v: -1}
}
func minimumCost(source string, target string, original []string, changed []string, cost []int) int64 {
inf := 1 << 60
root := newNode()
idx := 0
m := len(cost)
g := make([][]int, m<<1)
for i := range g {
g[i] = make([]int, m<<1)
for j := range g[i] {
g[i][j] = inf
}
g[i][i] = 0
}
insert := func(w string) int {
node := root
for _, c := range w {
i := c - 'a'
if node.children[i] == nil {
node.children[i] = newNode()
}
node = node.children[i]
}
if node.v < 0 {
node.v = idx
idx++
}
return node.v
}
for i := range original {
x := insert(original[i])
y := insert(changed[i])
g[x][y] = min(g[x][y], cost[i])
}
for k := 0; k < idx; k++ {
for i := 0; i < idx; i++ {
if g[i][k] >= inf {
continue
}
for j := 0; j < idx; j++ {
g[i][j] = min(g[i][j], g[i][k]+g[k][j])
}
}
}
n := len(source)
f := make([]int, n)
for i := range f {
f[i] = -1
}
var dfs func(int) int
dfs = func(i int) int {
if i >= n {
return 0
}
if f[i] >= 0 {
return f[i]
}
f[i] = inf
if source[i] == target[i] {
f[i] = dfs(i + 1)
}
p, q := root, root
for j := i; j < n; j++ {
p = p.children[source[j]-'a']
q = q.children[target[j]-'a']
if p == nil || q == nil {
break
}
if p.v < 0 || q.v < 0 {
continue
}
f[i] = min(f[i], dfs(j+1)+g[p.v][q.v])
}
return f[i]
}
ans := dfs(0)
if ans >= inf {
ans = -1
}
return int64(ans)
}use std::cmp::min;
struct Node {
children: [Option<Box<Node>>; 26],
v: i32,
}
impl Node {
fn new() -> Self {
Self {
children: std::array::from_fn(|_| None),
v: -1,
}
}
}
impl Solution {
pub fn minimum_cost(
source: String,
target: String,
original: Vec<String>,
changed: Vec<String>,
cost: Vec<i32>,
) -> i64 {
let inf: i64 = 1 << 60;
let mut root = Box::new(Node::new());
let mut idx: usize = 0;
let m = cost.len();
let n = m << 1;
let mut g = vec![vec![inf; n]; n];
for i in 0..n {
g[i][i] = 0;
}
let mut insert = |w: &str, root: &mut Box<Node>, idx: &mut usize| -> usize {
let mut node: &mut Box<Node> = root;
for c in w.bytes() {
let i = (c - b'a') as usize;
if node.children[i].is_none() {
node.children[i] = Some(Box::new(Node::new()));
}
node = node.children[i].as_mut().unwrap();
}
if node.v < 0 {
node.v = *idx as i32;
*idx += 1;
}
node.v as usize
};
for i in 0..m {
let x = insert(&original[i], &mut root, &mut idx);
let y = insert(&changed[i], &mut root, &mut idx);
g[x][y] = min(g[x][y], cost[i] as i64);
}
for k in 0..idx {
for i in 0..idx {
if g[i][k] >= inf {
continue;
}
for j in 0..idx {
let v = g[i][k] + g[k][j];
if v < g[i][j] {
g[i][j] = v;
}
}
}
}
let s = source.into_bytes();
let t = target.into_bytes();
let len = s.len();
let mut f: Vec<Option<i64>> = vec![None; len];
fn dfs(
i: usize,
s: &[u8],
t: &[u8],
root: &Box<Node>,
g: &Vec<Vec<i64>>,
f: &mut Vec<Option<i64>>,
inf: i64,
) -> i64 {
if i >= s.len() {
return 0;
}
if let Some(v) = f[i] {
return v;
}
let mut res = if s[i] == t[i] {
dfs(i + 1, s, t, root, g, f, inf)
} else {
inf
};
let mut p: Option<&Box<Node>> = Some(root);
let mut q: Option<&Box<Node>> = Some(root);
for j in i..s.len() {
p = p.and_then(|x| x.children[(s[j] - b'a') as usize].as_ref());
q = q.and_then(|x| x.children[(t[j] - b'a') as usize].as_ref());
if p.is_none() || q.is_none() {
break;
}
let pv = p.unwrap().v;
let qv = q.unwrap().v;
if pv < 0 || qv < 0 {
continue;
}
let c = g[pv as usize][qv as usize];
if c < inf {
let v = c + dfs(j + 1, s, t, root, g, f, inf);
if v < res {
res = v;
}
}
}
f[i] = Some(res);
res
}
let ans = dfs(0, &s, &t, &root, &g, &mut f, inf);
if ans >= inf { -1 } else { ans }
}
}Complexity comparison
| Approach | Complexity |
|---|---|
| Approach 1: Dynamic Programming | Time Complexity: O(n * m * l), where l is the length of each substring (original[i]). Space Complexity: O(n). |
| Approach 2: DFS with Memoization | Time Complexity: Approximately O(n * m), which is less than the full combinatorial exploration due to memoization. Space Complexity: O(n) for storing results of recursion and memoization cache. |
| Trie + Floyd Algorithm + Memoization Search | – |
Complexity analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Dynamic Programming + Trie + Shortest Path | O(n·L + k^3) | O(k^2 + n) | Best general solution when many substring rules exist and chaining conversions is allowed |
| DFS with Memoization | O(n·L + states) | O(n) | Simpler top‑down implementation, good for Python when recursion depth is manageable |
Frequently asked questions
Is Minimum Cost to Convert String II easy or hard?
Minimum Cost to Convert String II is classified as Hard. It requires combining multiple concepts—graph shortest paths, Trie-based substring matching, and dynamic programming—making it significantly more complex than standard string transformation problems.
Minimum Cost to Convert String II Python/Java solution
In Python or Java, the typical implementation builds a graph for substring transformations, runs Floyd–Warshall (or repeated Dijkstra) to compute minimum costs, and then performs dynamic programming over the string indices. A Trie or hash‑based prefix matching structure speeds up substring checks.
How to solve Minimum Cost to Convert String II in O(n)?
A strict O(n) solution is not feasible because substring transformations must be checked and the rule graph requires shortest path preprocessing. The closest practical complexity is O(n·L) for the DP scanning phase, after an O(k^3) preprocessing step for computing minimum conversion costs between patterns.
What is the best approach for Minimum Cost to Convert String II?
The most reliable solution combines dynamic programming with a Trie and a shortest path preprocessing step. Treat every substring rule as an edge in a graph and compute minimum conversion costs between patterns using Floyd–Warshall. Then run DP over the source string and match substrings using a Trie to update the minimum cost efficiently.
Is Minimum Cost to Convert String II asked at Google/Amazon/Meta?
Hard string and graph hybrid problems like this commonly appear in interviews at companies such as Google, Amazon, and Meta. The problem tests multiple skills: graph modeling, shortest path algorithms, and dynamic programming over strings.
What data structure is used in Minimum Cost to Convert String II?
The solution typically uses a Trie to efficiently match substring rules while scanning the source and target strings. A graph structure stores transformation rules, and shortest path algorithms compute minimum conversion costs between patterns before the DP step.
What is the time complexity of Minimum Cost to Convert String II?
The optimized solution runs in O(n·L + k^3) time, where n is the length of the string, L is the maximum rule length checked with the Trie, and k is the number of unique transformation patterns used in the shortest‑path preprocessing. Space complexity is typically O(k^2 + n).
