Skip to content

Commit c638c4e

Browse files
committed
Added task 3521
1 parent b98587f commit c638c4e

File tree

2 files changed

+178
-27
lines changed
  • src
    • main/kotlin/g3501_3600/s3525_find_x_value_of_array_ii
    • test/kotlin/g3501_3600/s3521_find_product_recommendation_pairs

2 files changed

+178
-27
lines changed
Lines changed: 84 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,93 @@
11
package g3501_3600.s3525_find_x_value_of_array_ii
22

3-
// #Hard #2025_04_20_Time_9_ms_(100.00%)_Space_84.76_MB_(100.00%)
3+
// #Hard #Array #Math #Segment_Tree #2025_04_22_Time_237_ms_(50.00%)_Space_114.07_MB_(50.00%)
44

55
class Solution {
6+
private var k: Int = 0
7+
private lateinit var seg: Array<Node?>
8+
private lateinit var nums: IntArray
9+
10+
private inner class Node {
11+
var prod: Int = 1 % k
12+
var cnt: IntArray = IntArray(k)
13+
}
14+
15+
private fun merge(l: Node, r: Node): Node {
16+
val p = Node()
17+
p.prod = (l.prod * r.prod) % k
18+
if (k >= 0) {
19+
System.arraycopy(l.cnt, 0, p.cnt, 0, k)
20+
}
21+
for (t in 0 until k) {
22+
val w = (l.prod * t) % k
23+
p.cnt[w] += r.cnt[t]
24+
}
25+
return p
26+
}
27+
28+
private fun build(idx: Int, l: Int, r: Int) {
29+
if (l == r) {
30+
val nd = Node()
31+
val v = nums[l] % k
32+
nd.prod = v
33+
nd.cnt[v] = 1
34+
seg[idx] = nd
35+
} else {
36+
val m = (l + r) ushr 1
37+
build(idx shl 1, l, m)
38+
build((idx shl 1) or 1, m + 1, r)
39+
seg[idx] = merge(seg[idx shl 1]!!, seg[(idx shl 1) or 1]!!)
40+
}
41+
}
42+
43+
private fun update(idx: Int, l: Int, r: Int, pos: Int, `val`: Int) {
44+
if (l == r) {
45+
val nd = Node()
46+
val v = `val` % k
47+
nd.prod = v
48+
nd.cnt[v] = 1
49+
seg[idx] = nd
50+
} else {
51+
val m = (l + r) ushr 1
52+
if (pos <= m) {
53+
update(idx shl 1, l, m, pos, `val`)
54+
} else {
55+
update((idx shl 1) or 1, m + 1, r, pos, `val`)
56+
}
57+
seg[idx] = merge(seg[idx shl 1]!!, seg[(idx shl 1) or 1]!!)
58+
}
59+
}
60+
61+
private fun query(idx: Int, l: Int, r: Int, ql: Int, qr: Int): Node {
62+
if (ql <= l && r <= qr) {
63+
return seg[idx]!!
64+
}
65+
val m = (l + r) ushr 1
66+
if (qr <= m) {
67+
return query(idx shl 1, l, m, ql, qr)
68+
}
69+
if (ql > m) {
70+
return query((idx shl 1) or 1, m + 1, r, ql, qr)
71+
}
72+
return merge(query(idx shl 1, l, m, ql, qr), query((idx shl 1) or 1, m + 1, r, ql, qr))
73+
}
74+
675
fun resultArray(nums: IntArray, k: Int, queries: Array<IntArray>): IntArray {
7-
val result = IntArray(queries.size)
76+
val n = nums.size
77+
this.k = k
78+
this.nums = nums
79+
seg = arrayOfNulls(4 * n)
80+
build(1, 0, n - 1)
81+
val ans = IntArray(queries.size)
882
for (i in queries.indices) {
9-
val q = queries[i]
10-
val index = q[0]
11-
val value = q[1]
12-
val start = q[2]
13-
val x = q[3]
14-
nums[index] = value
15-
var count = 0
16-
var currentProduct = 1
17-
var lProcessed = 0
18-
for (j in start..<nums.size) {
19-
currentProduct = (currentProduct * (nums[j] % k)) % k
20-
lProcessed++
21-
if (currentProduct == x) {
22-
count++
23-
}
24-
if (currentProduct == 0) {
25-
if (x == 0) {
26-
val remaining = (nums.size - start) - lProcessed
27-
count += remaining
28-
}
29-
break
30-
}
31-
}
32-
result[i] = count
83+
val idx0 = queries[i][0]
84+
val `val` = queries[i][1]
85+
val start = queries[i][2]
86+
val x = queries[i][3]
87+
update(1, 0, n - 1, idx0, `val`)
88+
val res = query(1, 0, n - 1, start, n - 1)
89+
ans[i] = res.cnt[x]
3390
}
34-
return result
91+
return ans
3592
}
3693
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package g3501_3600.s3521_find_product_recommendation_pairs
2+
3+
import org.hamcrest.CoreMatchers
4+
import org.hamcrest.MatcherAssert
5+
import org.junit.jupiter.api.Test
6+
import org.zapodot.junit.db.annotations.EmbeddedDatabase
7+
import org.zapodot.junit.db.annotations.EmbeddedDatabaseTest
8+
import org.zapodot.junit.db.common.CompatibilityMode
9+
import java.io.BufferedReader
10+
import java.io.FileNotFoundException
11+
import java.io.FileReader
12+
import java.sql.ResultSet
13+
import java.sql.SQLException
14+
import java.util.stream.Collectors
15+
import javax.sql.DataSource
16+
17+
@EmbeddedDatabaseTest(
18+
compatibilityMode = CompatibilityMode.MySQL,
19+
initialSqls = [
20+
(
21+
" CREATE TABLE ProductPurchases (" +
22+
" user_id INT," +
23+
" product_id INT," +
24+
" quantity INT" +
25+
");" +
26+
"CREATE TABLE ProductInfo (" +
27+
" product_id INT," +
28+
" category VARCHAR(100)," +
29+
" price BIGINT" +
30+
");" +
31+
"INSERT INTO ProductPurchases (user_id, product_id, quantity)" +
32+
"VALUES" +
33+
" (1 , 101 , 2)," +
34+
" (1 , 102 , 1 )," +
35+
" (1 , 103 , 3 )," +
36+
" (2 , 101 , 1 )," +
37+
" (2 , 102 , 5 )," +
38+
" (2 , 104 , 1 )," +
39+
" (3 , 101 , 2 )," +
40+
" (3 , 103 , 1 )," +
41+
" (3 , 105 , 4 )," +
42+
" (4 , 101 , 1 )," +
43+
" (4 , 102 , 1 )," +
44+
" (4 , 103 , 2 )," +
45+
" (4 , 104 , 3 )," +
46+
" (5 , 102 , 2 )," +
47+
" (5 , 104 , 1 );" +
48+
"INSERT INTO ProductInfo (product_id, category, price)" +
49+
"VALUES" +
50+
" (101 , 'Electronics' , 100)," +
51+
" (102 , 'Books' , 20)," +
52+
" (103 , 'Clothing' , 35)," +
53+
" (104 , 'Kitchen' , 50)," +
54+
" (105 , 'Sports' , 75);"
55+
),
56+
],
57+
)
58+
internal class MysqlTest {
59+
@Test
60+
@Throws(SQLException::class, FileNotFoundException::class)
61+
fun testScript(@EmbeddedDatabase dataSource: DataSource) {
62+
dataSource.connection.use { connection ->
63+
connection.createStatement().use { statement ->
64+
statement.executeQuery(
65+
BufferedReader(
66+
FileReader(
67+
(
68+
"src/main/kotlin/g3501_3600/" +
69+
"s3521_find_product_recommendation_pairs/" +
70+
"script.sql"
71+
),
72+
),
73+
)
74+
.lines()
75+
.collect(Collectors.joining("\n"))
76+
.replace("#.*\\r\\n".toRegex(), ""),
77+
).use { resultSet ->
78+
checkRow(resultSet, arrayOf<String>("101", "102", "Electronics", "Books", "3"))
79+
checkRow(resultSet, arrayOf<String>("101", "103", "Electronics", "Clothing", "3"))
80+
checkRow(resultSet, arrayOf<String>("102", "104", "Books", "Clothing", "3"))
81+
MatcherAssert.assertThat<Boolean>(resultSet.next(), CoreMatchers.equalTo<Boolean>(false))
82+
}
83+
}
84+
}
85+
}
86+
87+
@Throws(SQLException::class)
88+
private fun checkRow(resultSet: ResultSet, values: Array<String>) {
89+
MatcherAssert.assertThat<Boolean>(resultSet.next(), CoreMatchers.equalTo<Boolean>(true))
90+
MatcherAssert.assertThat<String>(resultSet.getNString(1), CoreMatchers.equalTo<String>(values[0]))
91+
MatcherAssert.assertThat<String>(resultSet.getNString(2), CoreMatchers.equalTo<String>(values[1]))
92+
MatcherAssert.assertThat<String>(resultSet.getNString(3), CoreMatchers.equalTo<String>(values[2]))
93+
}
94+
}

0 commit comments

Comments
 (0)