Skip to content

Commit f6816b6

Browse files
authored
Improved task 3213
1 parent 6f0d1dc commit f6816b6

File tree

1 file changed

+129
-40
lines changed
  • src/main/kotlin/g3201_3300/s3213_construct_string_with_minimum_cost

1 file changed

+129
-40
lines changed
Lines changed: 129 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,155 @@
11
package g3201_3300.s3213_construct_string_with_minimum_cost
22

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

6+
import java.util.Collections
7+
import kotlin.collections.ArrayList
8+
import kotlin.collections.HashMap
69
import kotlin.math.min
710

11+
@Suppress("NAME_SHADOWING")
812
class Solution {
9-
private class Node {
10-
var cost: Int = -1
11-
var chd: Array<Node?> = arrayOfNulls(26)
13+
private fun buildKmpPrefix(target: String): List<Int> {
14+
val w: MutableList<Int> = ArrayList(Collections.nCopies(target.length, 0))
15+
var k = 0
16+
var i = 1
17+
while (i < target.length) {
18+
if (target[i] == target[k]) {
19+
k++
20+
w[i] = k
21+
i++
22+
} else {
23+
if (k != 0) {
24+
k = w[k - 1]
25+
} else {
26+
i++
27+
}
28+
}
29+
}
30+
return w
1231
}
1332

14-
private var rt: Node? = null
33+
fun find(prefix: List<Int>, target: String, w: String): List<List<Int>> {
34+
val result: MutableList<List<Int>> = ArrayList()
35+
val m = target.length
36+
val n = w.length
37+
var i = 0
38+
var k = 0
39+
while (i < m) {
40+
if (target[i] == w[k]) {
41+
i++
42+
k++
43+
}
44+
if (k == n) {
45+
result.add(listOf(i - k, i))
46+
k = prefix[k - 1]
47+
} else if (i < m && target[i] != w[k]) {
48+
if (k != 0) {
49+
k = prefix[k - 1]
50+
} else {
51+
i++
52+
}
53+
}
54+
}
55+
return result
56+
}
1557

1658
fun minimumCost(target: String, words: Array<String>, costs: IntArray): Int {
17-
rt = Node()
18-
val m = words.size
19-
val n = target.length
20-
for (i in 0 until m) {
21-
if (words[i].length <= n) {
22-
insert(words[i], costs[i])
59+
val targetPrefix = buildKmpPrefix(target)
60+
val root = Node()
61+
for (j in words.indices) {
62+
val x = words[j]
63+
if (x.length < 320) {
64+
var p: Node? = root
65+
for (i in 0 until x.length) {
66+
val c = x[i]
67+
p!!.children.putIfAbsent(c, Node())
68+
p = p.children[c]
69+
if (i == x.length - 1) {
70+
if (p!!.cost == null) {
71+
p.cost = costs[j]
72+
} else {
73+
p.cost = min(costs[j], p.cost!!)
74+
}
75+
}
76+
}
2377
}
2478
}
25-
val dp = IntArray(n + 1)
26-
dp.fill(INVALID)
79+
val dm =
80+
getIntegerMapMap(target, words, costs, targetPrefix)
81+
var d: MutableList<NodeCostPair> = ArrayList()
82+
d.add(NodeCostPair(root, 0))
83+
val dp = IntArray(target.length + 1)
84+
dp.fill(-1)
2785
dp[0] = 0
28-
for (i in 0 until n) {
29-
if (dp[i] == INVALID) {
30-
continue
31-
}
32-
val nowC = dp[i]
33-
var now = rt
34-
var j = i
35-
while (now != null && j < n) {
36-
val ch = target[j].code - 'a'.code
37-
now = now.chd[ch]
38-
if (now != null && now.cost != -1) {
39-
dp[j + 1] = min(dp[j + 1].toDouble(), (nowC + now.cost).toDouble()).toInt()
86+
for (i in target.indices) {
87+
val x = target[i]
88+
val q: MutableList<NodeCostPair> = ArrayList()
89+
var t: Int? = null
90+
for (pair in d) {
91+
val p = pair.node
92+
val cost = pair.cost
93+
if (p!!.children.containsKey(x)) {
94+
val w = p.children[x]
95+
if (w!!.cost != null) {
96+
t = if (t == null) cost + w.cost!! else min(t, (cost + w.cost!!))
97+
}
98+
q.add(NodeCostPair(w, cost))
4099
}
41-
++j
42100
}
101+
t = getInteger(dm, i, dp, t)
102+
if (t != null) {
103+
dp[i + 1] = t
104+
q.add(NodeCostPair(root, t))
105+
}
106+
d = q
43107
}
44-
45-
return if (dp[n] == INVALID) -1 else dp[n]
108+
return dp[target.length]
46109
}
47110

48-
private fun insert(wd: String, cst: Int) {
49-
val len = wd.length
50-
var now = rt
51-
for (i in 0 until len) {
52-
val ch = wd[i].code - 'a'.code
53-
if (now!!.chd[ch] == null) {
54-
now.chd[ch] = Node()
111+
private fun getInteger(dm: Map<Int, MutableMap<Int, Int>>, i: Int, dp: IntArray, t: Int?): Int? {
112+
var t = t
113+
val qm = dm.getOrDefault(i + 1, emptyMap())
114+
for ((b, value) in qm) {
115+
if (dp[b] >= 0) {
116+
t = if (t == null) dp[b] + value else min(t, (dp[b] + value))
55117
}
56-
now = now.chd[ch]
57118
}
58-
if (now!!.cost == -1 || now.cost > cst) {
59-
now.cost = cst
119+
return t
120+
}
121+
122+
private fun getIntegerMapMap(
123+
target: String,
124+
words: Array<String>,
125+
costs: IntArray,
126+
targetPrefix: List<Int>
127+
): Map<Int, MutableMap<Int, Int>> {
128+
val dm: MutableMap<Int, MutableMap<Int, Int>> = HashMap()
129+
for (i in words.indices) {
130+
val word = words[i]
131+
if (word.length >= 320) {
132+
val q = find(targetPrefix, target, word)
133+
for (pair in q) {
134+
val b = pair[0]
135+
val e = pair[1]
136+
dm.putIfAbsent(e, HashMap())
137+
val qm = dm[e]!!
138+
if (qm.containsKey(b)) {
139+
qm[b] = min(qm[b]!!, costs[i])
140+
} else {
141+
qm[b] = costs[i]
142+
}
143+
}
144+
}
60145
}
146+
return dm
61147
}
62148

63-
companion object {
64-
private const val INVALID = Int.MAX_VALUE
149+
private class Node {
150+
var children: MutableMap<Char, Node> = HashMap()
151+
var cost: Int? = null
65152
}
153+
154+
private class NodeCostPair(var node: Node?, var cost: Int)
66155
}

0 commit comments

Comments
 (0)