Skip to content

Commit

Permalink
Improved task 3213
Browse files Browse the repository at this point in the history
  • Loading branch information
javadev authored Jul 15, 2024
1 parent f6816b6 commit 4a64b8b
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 125 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
plugins {
kotlin("jvm") version "2.0.0"
jacoco
id("org.sonarqube") version "5.0.0.4638"
id("org.sonarqube") version "5.1.0.4882"
id("com.diffplug.spotless") version "6.12.0"
`maven-publish`
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,155 +1,100 @@
package g3201_3300.s3213_construct_string_with_minimum_cost

// #Hard #Array #String #Dynamic_Programming #Suffix_Array
// #2024_07_15_Time_3201_ms_(6.67%)_Space_114.1_MB_(6.67%)
// #2024_07_15_Time_1176_ms_(46.67%)_Space_78.1_MB_(33.33%)

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

@Suppress("NAME_SHADOWING")
class Solution {
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++
}
}
private class ACAutomaton {
class Node {
var key: Char = 0.toChar()
var `val`: Int? = null
var len: Int = 0
val next: Array<Node?> = arrayOfNulls(26)
var suffix: Node? = null
var output: Node? = null
var parent: Node? = null
}
return w
}

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++
fun build(patterns: Array<String>, values: IntArray): Node {
val root = Node()
root.suffix = root
root.output = root
for (i in patterns.indices) {
put(root, patterns[i], values[i])
}
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]
for (i in root.next.indices) {
if (root.next[i] == null) {
root.next[i] = root
} else {
i++
root.next[i]!!.suffix = root
}
}
return root
}
return result
}

fun minimumCost(target: String, words: Array<String>, costs: IntArray): Int {
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!!)
}
}
private fun put(root: Node, s: String, `val`: Int) {
var node: Node? = root
for (c in s.toCharArray()) {
if (node!!.next[c.code - 'a'.code] == null) {
node.next[c.code - 'a'.code] = Node()
node.next[c.code - 'a'.code]!!.parent = node
node.next[c.code - 'a'.code]!!.key = c
}
node = node.next[c.code - 'a'.code]
}
}
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 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))
}
if (node!!.`val` == null || node.`val`!! > `val`) {
node.`val` = `val`
node.len = s.length
}
t = getInteger(dm, i, dp, t)
if (t != null) {
dp[i + 1] = t
q.add(NodeCostPair(root, t))
}

fun getOutput(node: Node?): Node? {
if (node!!.output == null) {
val suffix = getSuffix(node)
node.output = if (suffix!!.`val` != null) suffix else getOutput(suffix)
}
d = q
return node.output
}
return dp[target.length]
}

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))
fun go(node: Node?, c: Char): Node? {
if (node!!.next[c.code - 'a'.code] == null) {
node.next[c.code - 'a'.code] = go(getSuffix(node), c)
}
return node.next[c.code - 'a'.code]
}
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]
}
private fun getSuffix(node: Node?): Node? {
if (node!!.suffix == null) {
node.suffix = go(getSuffix(node.parent), node.key)
if (node.suffix!!.`val` != null) {
node.output = node.suffix
} else {
node.output = node.suffix!!.output
}
}
return node.suffix
}
return dm
}

private class Node {
var children: MutableMap<Char, Node> = HashMap()
var cost: Int? = null
fun minimumCost(target: String, words: Array<String>, costs: IntArray): Int {
val ac = ACAutomaton()
val root = ac.build(words, costs)
val dp = IntArray(target.length + 1)
dp.fill(Int.MAX_VALUE / 2)
dp[0] = 0
var node: ACAutomaton.Node? = root
for (i in 1 until dp.size) {
node = ac.go(node, target[i - 1])
var temp = node
while (temp != null && temp !== root) {
if (temp.`val` != null && dp[i - temp.len] < Int.MAX_VALUE / 2) {
dp[i] = min(dp[i], (dp[i - temp.len] + temp.`val`!!))
}
temp = ac.getOutput(temp)
}
}
return if (dp[dp.size - 1] >= Int.MAX_VALUE / 2) -1 else dp[dp.size - 1]
}

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

0 comments on commit 4a64b8b

Please sign in to comment.