Skip to content

Improved task 3213 #667

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 15, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,66 +1,155 @@
package g3201_3300.s3213_construct_string_with_minimum_cost

// #Hard #Array #String #Dynamic_Programming #Suffix_Array
// #2024_07_09_Time_182_ms_(100.00%)_Space_61.4_MB_(72.97%)
// #2024_07_15_Time_3201_ms_(6.67%)_Space_114.1_MB_(6.67%)

import java.util.Collections
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
import kotlin.math.min

@Suppress("NAME_SHADOWING")
class Solution {
private class Node {
var cost: Int = -1
var chd: Array<Node?> = arrayOfNulls(26)
private fun buildKmpPrefix(target: String): List<Int> {
val w: MutableList<Int> = ArrayList(Collections.nCopies(target.length, 0))
var k = 0
var i = 1
while (i < target.length) {
if (target[i] == target[k]) {
k++
w[i] = k
i++
} else {
if (k != 0) {
k = w[k - 1]
} else {
i++
}
}
}
return w
}

private var rt: Node? = null
fun find(prefix: List<Int>, target: String, w: String): List<List<Int>> {
val result: MutableList<List<Int>> = ArrayList()
val m = target.length
val n = w.length
var i = 0
var k = 0
while (i < m) {
if (target[i] == w[k]) {
i++
k++
}
if (k == n) {
result.add(listOf(i - k, i))
k = prefix[k - 1]
} else if (i < m && target[i] != w[k]) {
if (k != 0) {
k = prefix[k - 1]
} else {
i++
}
}
}
return result
}

fun minimumCost(target: String, words: Array<String>, costs: IntArray): Int {
rt = Node()
val m = words.size
val n = target.length
for (i in 0 until m) {
if (words[i].length <= n) {
insert(words[i], costs[i])
val targetPrefix = buildKmpPrefix(target)
val root = Node()
for (j in words.indices) {
val x = words[j]
if (x.length < 320) {
var p: Node? = root
for (i in 0 until x.length) {
val c = x[i]
p!!.children.putIfAbsent(c, Node())
p = p.children[c]
if (i == x.length - 1) {
if (p!!.cost == null) {
p.cost = costs[j]
} else {
p.cost = min(costs[j], p.cost!!)
}
}
}
}
}
val dp = IntArray(n + 1)
dp.fill(INVALID)
val dm =
getIntegerMapMap(target, words, costs, targetPrefix)
var d: MutableList<NodeCostPair> = ArrayList()
d.add(NodeCostPair(root, 0))
val dp = IntArray(target.length + 1)
dp.fill(-1)
dp[0] = 0
for (i in 0 until n) {
if (dp[i] == INVALID) {
continue
}
val nowC = dp[i]
var now = rt
var j = i
while (now != null && j < n) {
val ch = target[j].code - 'a'.code
now = now.chd[ch]
if (now != null && now.cost != -1) {
dp[j + 1] = min(dp[j + 1].toDouble(), (nowC + now.cost).toDouble()).toInt()
for (i in target.indices) {
val x = target[i]
val q: MutableList<NodeCostPair> = ArrayList()
var t: Int? = null
for (pair in d) {
val p = pair.node
val cost = pair.cost
if (p!!.children.containsKey(x)) {
val w = p.children[x]
if (w!!.cost != null) {
t = if (t == null) cost + w.cost!! else min(t, (cost + w.cost!!))
}
q.add(NodeCostPair(w, cost))
}
++j
}
t = getInteger(dm, i, dp, t)
if (t != null) {
dp[i + 1] = t
q.add(NodeCostPair(root, t))
}
d = q
}

return if (dp[n] == INVALID) -1 else dp[n]
return dp[target.length]
}

private fun insert(wd: String, cst: Int) {
val len = wd.length
var now = rt
for (i in 0 until len) {
val ch = wd[i].code - 'a'.code
if (now!!.chd[ch] == null) {
now.chd[ch] = Node()
private fun getInteger(dm: Map<Int, MutableMap<Int, Int>>, i: Int, dp: IntArray, t: Int?): Int? {
var t = t
val qm = dm.getOrDefault(i + 1, emptyMap())
for ((b, value) in qm) {
if (dp[b] >= 0) {
t = if (t == null) dp[b] + value else min(t, (dp[b] + value))
}
now = now.chd[ch]
}
if (now!!.cost == -1 || now.cost > cst) {
now.cost = cst
return t
}

private fun getIntegerMapMap(
target: String,
words: Array<String>,
costs: IntArray,
targetPrefix: List<Int>
): Map<Int, MutableMap<Int, Int>> {
val dm: MutableMap<Int, MutableMap<Int, Int>> = HashMap()
for (i in words.indices) {
val word = words[i]
if (word.length >= 320) {
val q = find(targetPrefix, target, word)
for (pair in q) {
val b = pair[0]
val e = pair[1]
dm.putIfAbsent(e, HashMap())
val qm = dm[e]!!
if (qm.containsKey(b)) {
qm[b] = min(qm[b]!!, costs[i])
} else {
qm[b] = costs[i]
}
}
}
}
return dm
}

companion object {
private const val INVALID = Int.MAX_VALUE
private class Node {
var children: MutableMap<Char, Node> = HashMap()
var cost: Int? = null
}

private class NodeCostPair(var node: Node?, var cost: Int)
}