Skip to content

Commit 4a64b8b

Browse files
authored
Improved task 3213
1 parent f6816b6 commit 4a64b8b

File tree

2 files changed

+70
-125
lines changed

2 files changed

+70
-125
lines changed

build.gradle.kts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
plugins {
22
kotlin("jvm") version "2.0.0"
33
jacoco
4-
id("org.sonarqube") version "5.0.0.4638"
4+
id("org.sonarqube") version "5.1.0.4882"
55
id("com.diffplug.spotless") version "6.12.0"
66
`maven-publish`
77
}
Original file line numberDiff line numberDiff line change
@@ -1,155 +1,100 @@
11
package g3201_3300.s3213_construct_string_with_minimum_cost
22

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

6-
import java.util.Collections
7-
import kotlin.collections.ArrayList
8-
import kotlin.collections.HashMap
96
import kotlin.math.min
107

11-
@Suppress("NAME_SHADOWING")
128
class Solution {
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-
}
9+
private class ACAutomaton {
10+
class Node {
11+
var key: Char = 0.toChar()
12+
var `val`: Int? = null
13+
var len: Int = 0
14+
val next: Array<Node?> = arrayOfNulls(26)
15+
var suffix: Node? = null
16+
var output: Node? = null
17+
var parent: Node? = null
2918
}
30-
return w
31-
}
3219

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++
20+
fun build(patterns: Array<String>, values: IntArray): Node {
21+
val root = Node()
22+
root.suffix = root
23+
root.output = root
24+
for (i in patterns.indices) {
25+
put(root, patterns[i], values[i])
4326
}
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]
27+
for (i in root.next.indices) {
28+
if (root.next[i] == null) {
29+
root.next[i] = root
5030
} else {
51-
i++
31+
root.next[i]!!.suffix = root
5232
}
5333
}
34+
return root
5435
}
55-
return result
56-
}
5736

58-
fun minimumCost(target: String, words: Array<String>, costs: IntArray): Int {
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-
}
37+
private fun put(root: Node, s: String, `val`: Int) {
38+
var node: Node? = root
39+
for (c in s.toCharArray()) {
40+
if (node!!.next[c.code - 'a'.code] == null) {
41+
node.next[c.code - 'a'.code] = Node()
42+
node.next[c.code - 'a'.code]!!.parent = node
43+
node.next[c.code - 'a'.code]!!.key = c
7644
}
45+
node = node.next[c.code - 'a'.code]
7746
}
78-
}
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)
85-
dp[0] = 0
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))
99-
}
47+
if (node!!.`val` == null || node.`val`!! > `val`) {
48+
node.`val` = `val`
49+
node.len = s.length
10050
}
101-
t = getInteger(dm, i, dp, t)
102-
if (t != null) {
103-
dp[i + 1] = t
104-
q.add(NodeCostPair(root, t))
51+
}
52+
53+
fun getOutput(node: Node?): Node? {
54+
if (node!!.output == null) {
55+
val suffix = getSuffix(node)
56+
node.output = if (suffix!!.`val` != null) suffix else getOutput(suffix)
10557
}
106-
d = q
58+
return node.output
10759
}
108-
return dp[target.length]
109-
}
11060

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))
61+
fun go(node: Node?, c: Char): Node? {
62+
if (node!!.next[c.code - 'a'.code] == null) {
63+
node.next[c.code - 'a'.code] = go(getSuffix(node), c)
11764
}
65+
return node.next[c.code - 'a'.code]
11866
}
119-
return t
120-
}
12167

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-
}
68+
private fun getSuffix(node: Node?): Node? {
69+
if (node!!.suffix == null) {
70+
node.suffix = go(getSuffix(node.parent), node.key)
71+
if (node.suffix!!.`val` != null) {
72+
node.output = node.suffix
73+
} else {
74+
node.output = node.suffix!!.output
14375
}
14476
}
77+
return node.suffix
14578
}
146-
return dm
14779
}
14880

149-
private class Node {
150-
var children: MutableMap<Char, Node> = HashMap()
151-
var cost: Int? = null
81+
fun minimumCost(target: String, words: Array<String>, costs: IntArray): Int {
82+
val ac = ACAutomaton()
83+
val root = ac.build(words, costs)
84+
val dp = IntArray(target.length + 1)
85+
dp.fill(Int.MAX_VALUE / 2)
86+
dp[0] = 0
87+
var node: ACAutomaton.Node? = root
88+
for (i in 1 until dp.size) {
89+
node = ac.go(node, target[i - 1])
90+
var temp = node
91+
while (temp != null && temp !== root) {
92+
if (temp.`val` != null && dp[i - temp.len] < Int.MAX_VALUE / 2) {
93+
dp[i] = min(dp[i], (dp[i - temp.len] + temp.`val`!!))
94+
}
95+
temp = ac.getOutput(temp)
96+
}
97+
}
98+
return if (dp[dp.size - 1] >= Int.MAX_VALUE / 2) -1 else dp[dp.size - 1]
15299
}
153-
154-
private class NodeCostPair(var node: Node?, var cost: Int)
155100
}

0 commit comments

Comments
 (0)