LeetCode in Kotlin

2977. Minimum Cost to Convert String II

Hard

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:

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:

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:

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:

Solution

import kotlin.math.min

class Solution {
    fun minimumCost(
        source: String,
        target: String,
        original: Array<String>,
        changed: Array<String>,
        cost: IntArray,
    ): Long {
        val index = HashMap<String, Int>()
        for (o in original) {
            if (!index.containsKey(o)) {
                index[o] = index.size
            }
        }
        for (c in changed) {
            if (!index.containsKey(c)) {
                index[c] = index.size
            }
        }
        val dis = Array(index.size) { LongArray(index.size) }
        for (i in dis.indices) {
            dis[i].fill(Long.MAX_VALUE)
            dis[i][i] = 0
        }
        for (i in cost.indices) {
            dis[index[original[i]]!!][index[changed[i]]!!] =
                min(dis[index[original[i]]!!][index[changed[i]]!!], cost[i].toLong())
        }
        for (k in dis.indices) {
            for (i in dis.indices) {
                if (dis[i][k] < Long.MAX_VALUE) {
                    for (j in dis.indices) {
                        if (dis[k][j] < Long.MAX_VALUE) {
                            dis[i][j] = min(dis[i][j], (dis[i][k] + dis[k][j]))
                        }
                    }
                }
            }
        }
        val set = HashSet<Int>()
        for (o in original) {
            set.add(o.length)
        }
        val dp = LongArray(target.length + 1)
        dp.fill(Long.MAX_VALUE)
        dp[0] = 0L
        for (i in target.indices) {
            if (dp[i] == Long.MAX_VALUE) {
                continue
            }
            if (target[i] == source[i]) {
                dp[i + 1] = min(dp[i + 1], dp[i])
            }
            for (t in set) {
                if (i + t >= dp.size) {
                    continue
                }
                val c1 = index.getOrDefault(source.substring(i, i + t), -1)
                val c2 = index.getOrDefault(target.substring(i, i + t), -1)
                if (c1 >= 0 && c2 >= 0 && dis[c1][c2] < Long.MAX_VALUE) {
                    dp[i + t] = min(dp[i + t], (dp[i] + dis[c1][c2]))
                }
            }
        }
        return if (dp[dp.size - 1] == Long.MAX_VALUE) -1L else dp[dp.size - 1]
    }
}