From efb59a8a71b0458c0e2b9b0facb56870d9cc0a66 Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Sun, 25 May 2025 18:03:27 +0300 Subject: [PATCH 1/6] Added tasks 3556-3663 --- .../Solution.kt | 44 +++++++++ .../readme.md | 36 +++++++ .../Solution.kt | 28 ++++++ .../readme.md | 32 ++++++ .../Solution.kt | 65 ++++++++++++ .../readme.md | 50 ++++++++++ .../Solution.kt | 98 +++++++++++++++++++ .../readme.md | 54 ++++++++++ .../Solution.kt | 22 +++++ .../readme.md | 37 +++++++ .../Solution.kt | 23 +++++ .../readme.md | 53 ++++++++++ .../Solution.kt | 96 ++++++++++++++++++ .../readme.md | 92 +++++++++++++++++ .../Solution.kt | 68 +++++++++++++ .../readme.md | 54 ++++++++++ .../SolutionTest.kt | 17 ++++ .../SolutionTest.kt | 17 ++++ .../SolutionTest.kt | 30 ++++++ .../SolutionTest.kt | 31 ++++++ .../SolutionTest.kt | 78 +++++++++++++++ .../SolutionTest.kt | 22 +++++ .../SolutionTest.kt | 55 +++++++++++ .../SolutionTest.kt | 31 ++++++ 24 files changed, 1133 insertions(+) create mode 100644 src/main/kotlin/g3501_3600/s3556_sum_of_largest_prime_substrings/Solution.kt create mode 100644 src/main/kotlin/g3501_3600/s3556_sum_of_largest_prime_substrings/readme.md create mode 100644 src/main/kotlin/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/Solution.kt create mode 100644 src/main/kotlin/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/readme.md create mode 100644 src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.kt create mode 100644 src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/readme.md create mode 100644 src/main/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/Solution.kt create mode 100644 src/main/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/readme.md create mode 100644 src/main/kotlin/g3501_3600/s3560_find_minimum_log_transportation_cost/Solution.kt create mode 100644 src/main/kotlin/g3501_3600/s3560_find_minimum_log_transportation_cost/readme.md create mode 100644 src/main/kotlin/g3501_3600/s3561_resulting_string_after_adjacent_removals/Solution.kt create mode 100644 src/main/kotlin/g3501_3600/s3561_resulting_string_after_adjacent_removals/readme.md create mode 100644 src/main/kotlin/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/Solution.kt create mode 100644 src/main/kotlin/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/readme.md create mode 100644 src/main/kotlin/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/Solution.kt create mode 100644 src/main/kotlin/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/readme.md create mode 100644 src/test/kotlin/g3501_3600/s3556_sum_of_largest_prime_substrings/SolutionTest.kt create mode 100644 src/test/kotlin/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/SolutionTest.kt create mode 100644 src/test/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/SolutionTest.kt create mode 100644 src/test/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/SolutionTest.kt create mode 100644 src/test/kotlin/g3501_3600/s3560_find_minimum_log_transportation_cost/SolutionTest.kt create mode 100644 src/test/kotlin/g3501_3600/s3561_resulting_string_after_adjacent_removals/SolutionTest.kt create mode 100644 src/test/kotlin/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/SolutionTest.kt create mode 100644 src/test/kotlin/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/SolutionTest.kt diff --git a/src/main/kotlin/g3501_3600/s3556_sum_of_largest_prime_substrings/Solution.kt b/src/main/kotlin/g3501_3600/s3556_sum_of_largest_prime_substrings/Solution.kt new file mode 100644 index 00000000..a297f43d --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3556_sum_of_largest_prime_substrings/Solution.kt @@ -0,0 +1,44 @@ +package g3501_3600.s3556_sum_of_largest_prime_substrings + +// #Medium #2025_05_25_Time_21_ms_(100.00%)_Space_42.82_MB_(100.00%) + +class Solution { + fun sumOfLargestPrimes(s: String): Long { + val primeSet: MutableSet = HashSet() + val n = s.length + for (i in 0.. = ArrayList(primeSet) + primes.sort() + val m = primes.size + if (m < 3) { + var sum: Long = 0 + for (p in primes) { + sum += p + } + return sum + } + return primes[m - 1] + primes[m - 2] + primes[m - 3] + } + + private fun isPrime(n: Long): Boolean { + if (n < 2) { + return false + } + var i: Long = 2 + while (i * i <= n) { + if (n % i == 0L) { + return false + } + ++i + } + return true + } +} diff --git a/src/main/kotlin/g3501_3600/s3556_sum_of_largest_prime_substrings/readme.md b/src/main/kotlin/g3501_3600/s3556_sum_of_largest_prime_substrings/readme.md new file mode 100644 index 00000000..c719d637 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3556_sum_of_largest_prime_substrings/readme.md @@ -0,0 +1,36 @@ +3556\. Sum of Largest Prime Substrings + +Medium + +Given a string `s`, find the sum of the **3 largest unique prime numbers** that can be formed using any of its ****substring****. + +Return the **sum** of the three largest unique prime numbers that can be formed. If fewer than three exist, return the sum of **all** available primes. If no prime numbers can be formed, return 0. + +**Note:** Each prime number should be counted only **once**, even if it appears in **multiple** substrings. Additionally, when converting a substring to an integer, any leading zeros are ignored. + +**Example 1:** + +**Input:** s = "12234" + +**Output:** 1469 + +**Explanation:** + +* The unique prime numbers formed from the substrings of `"12234"` are 2, 3, 23, 223, and 1223. +* The 3 largest primes are 1223, 223, and 23. Their sum is 1469. + +**Example 2:** + +**Input:** s = "111" + +**Output:** 11 + +**Explanation:** + +* The unique prime number formed from the substrings of `"111"` is 11. +* Since there is only one prime number, the sum is 11. + +**Constraints:** + +* `1 <= s.length <= 10` +* `s` consists of only digits. \ No newline at end of file diff --git a/src/main/kotlin/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/Solution.kt b/src/main/kotlin/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/Solution.kt new file mode 100644 index 00000000..501dc342 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/Solution.kt @@ -0,0 +1,28 @@ +package g3501_3600.s3557_find_maximum_number_of_non_intersecting_substrings + +import java.util.LinkedList +import kotlin.math.max + +// #Medium #2025_05_25_Time_103_ms_(100.00%)_Space_54.87_MB_(100.00%) + +class Solution { + fun maxSubstrings(s: String): Int { + val last: Array> = Array(26) { LinkedList() } + val n = s.length + val dp = IntArray(n + 1) + for (i in 0..= 4) { + dp[i + 1] = max(dp[i + 1], dp[j] + 1) + } + } + last[c].addLast(i) + if (last[c].size > 4) { + last[c].removeFirst() + } + } + return dp[n] + } +} diff --git a/src/main/kotlin/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/readme.md b/src/main/kotlin/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/readme.md new file mode 100644 index 00000000..6ba4e1b0 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/readme.md @@ -0,0 +1,32 @@ +3557\. Find Maximum Number of Non Intersecting Substrings + +Medium + +You are given a string `word`. + +Return the **maximum** number of non-intersecting ****substring**** of word that are at **least** four characters long and start and end with the same letter. + +**Example 1:** + +**Input:** word = "abcdeafdef" + +**Output:** 2 + +**Explanation:** + +The two substrings are `"abcdea"` and `"fdef"`. + +**Example 2:** + +**Input:** word = "bcdaaaab" + +**Output:** 1 + +**Explanation:** + +The only substring is `"aaaa"`. Note that we cannot **also** choose `"bcdaaaab"` since it intersects with the other substring. + +**Constraints:** + +* 1 <= word.length <= 2 * 105 +* `word` consists only of lowercase English letters. \ No newline at end of file diff --git a/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.kt b/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.kt new file mode 100644 index 00000000..3bcd0797 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.kt @@ -0,0 +1,65 @@ +package g3501_3600.s3558_number_of_ways_to_assign_edge_weights_i + +import java.util.* + +// #Medium #2025_05_25_Time_118_ms_(100.00%)_Space_122.30_MB_(100.00%) + +class Solution { + fun assignEdgeWeights(edges: Array): Int { + val n = edges.size + 1 + val adj: MutableList?> = ArrayList?>() + for (i in 0..n) { + adj.add(ArrayList()) + } + for (i in edges) { + adj.get(i[0])!!.add(i[1]) + adj.get(i[1])!!.add(i[0]) + } + val l = IntArray(n + 1) + var max = 0 + Arrays.fill(l, -1) + val q: Queue = LinkedList() + q.offer(intArrayOf(1, 0)) + l[1] = 0 + while (!q.isEmpty()) { + val curr = q.peek()!![0] + val level = q.peek()!![1] + if (l[max] < l[curr]) { + max = curr + } + q.remove() + for (next in adj.get(curr)!!) { + if (l[next!!] != -1) { + continue + } + q.offer(intArrayOf(next, level + 1)) + l[next] = level + 1 + } + } + val dp: Array = Array(l[max]) { IntArray(2) } + for (i in dp) { + Arrays.fill(i, -1) + } + return solve(0, 0, dp) + } + + private fun solve(ind: Int, odd: Int, dp: Array): Int { + if (ind == dp.size) { + if (odd == 1) { + return 1 + } else { + return 0 + } + } + if (dp[ind][odd] != -1) { + return dp[ind][odd] + } + dp[ind][odd] = + (solve(ind + 1, odd, dp) % MOD + solve(ind + 1, (odd + 1) % 2, dp) % MOD) % MOD + return dp[ind][odd] + } + + companion object { + private val MOD = 1e9.toInt() + 7 + } +} diff --git a/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/readme.md b/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/readme.md new file mode 100644 index 00000000..f6a7d4e8 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/readme.md @@ -0,0 +1,50 @@ +3558\. Number of Ways to Assign Edge Weights I + +Medium + +There is an undirected tree with `n` nodes labeled from 1 to `n`, rooted at node 1. The tree is represented by a 2D integer array `edges` of length `n - 1`, where edges[i] = [ui, vi] indicates that there is an edge between nodes ui and vi. + +Initially, all edges have a weight of 0. You must assign each edge a weight of either **1** or **2**. + +The **cost** of a path between any two nodes `u` and `v` is the total weight of all edges in the path connecting them. + +Select any one node `x` at the **maximum** depth. Return the number of ways to assign edge weights in the path from node 1 to `x` such that its total cost is **odd**. + +Since the answer may be large, return it **modulo** 109 + 7. + +**Note:** Ignore all edges **not** in the path from node 1 to `x`. + +**Example 1:** + +![](https://assets.leetcode.com/uploads/2025/03/23/screenshot-2025-03-24-at-060006.png) + +**Input:** edges = [[1,2]] + +**Output:** 1 + +**Explanation:** + +* The path from Node 1 to Node 2 consists of one edge (`1 → 2`). +* Assigning weight 1 makes the cost odd, while 2 makes it even. Thus, the number of valid assignments is 1. + +**Example 2:** + +![](https://assets.leetcode.com/uploads/2025/03/23/screenshot-2025-03-24-at-055820.png) + +**Input:** edges = [[1,2],[1,3],[3,4],[3,5]] + +**Output:** 2 + +**Explanation:** + +* The maximum depth is 2, with nodes 4 and 5 at the same depth. Either node can be selected for processing. +* For example, the path from Node 1 to Node 4 consists of two edges (`1 → 3` and `3 → 4`). +* Assigning weights (1,2) or (2,1) results in an odd cost. Thus, the number of valid assignments is 2. + +**Constraints:** + +* 2 <= n <= 105 +* `edges.length == n - 1` +* edges[i] == [ui, vi] +* 1 <= ui, vi <= n +* `edges` represents a valid tree. \ No newline at end of file diff --git a/src/main/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/Solution.kt b/src/main/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/Solution.kt new file mode 100644 index 00000000..cd47d42d --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/Solution.kt @@ -0,0 +1,98 @@ +package g3501_3600.s3559_number_of_ways_to_assign_edge_weights_ii + +import kotlin.math.ceil +import kotlin.math.ln + +// #Hard #2025_05_25_Time_135_ms_(100.00%)_Space_119.27_MB_(100.00%) + +class Solution { + private var adj: MutableList?>? = null + private lateinit var level: IntArray + private lateinit var jumps: Array + + private fun mark(node: Int, par: Int) { + for (neigh in adj!!.get(node)!!) { + if (neigh == par) { + continue + } + level[neigh!!] = level[node] + 1 + jumps[neigh]!![0] = node + mark(neigh, node) + } + } + + fun lift(u: Int, diff: Int): Int { + var u = u + var diff = diff + while (diff > 0) { + val rightmost = diff xor (diff and (diff - 1)) + val jump = (ln(rightmost.toDouble()) / ln(2.0)).toInt() + u = jumps[u]!![jump] + diff -= rightmost + } + return u + } + + private fun findLca(u: Int, v: Int): Int { + var u = u + var v = v + if (level[u] > level[v]) { + val temp = u + u = v + v = temp + } + v = lift(v, level[v] - level[u]) + if (u == v) { + return u + } + for (i in jumps[0]!!.indices.reversed()) { + if (jumps[u]!![i] != jumps[v]!![i]) { + u = jumps[u]!![i] + v = jumps[v]!![i] + } + } + return jumps[u]!![0] + } + + private fun findDist(a: Int, b: Int): Int { + return level[a] + level[b] - 2 * level[findLca(a, b)] + } + + fun assignEdgeWeights(edges: Array, queries: Array): IntArray { + val n = edges.size + 1 + adj = ArrayList?>() + level = IntArray(n) + for (i in 0..()) + } + for (i in edges) { + adj!!.get(i[0] - 1)!!.add(i[1] - 1) + adj!!.get(i[1] - 1)!!.add(i[0] - 1) + } + val m = (ceil(ln(n - 1.0) / ln(2.0))).toInt() + 1 + jumps = Array(n) { IntArray(m) } + mark(0, -1) + for (j in 1.. 0) pow[d - 1] else 0 + } + return ans + } + + companion object { + private const val MOD = 1000000007 + } +} diff --git a/src/main/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/readme.md b/src/main/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/readme.md new file mode 100644 index 00000000..f6072403 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/readme.md @@ -0,0 +1,54 @@ +3559\. Number of Ways to Assign Edge Weights II + +Hard + +There is an undirected tree with `n` nodes labeled from 1 to `n`, rooted at node 1. The tree is represented by a 2D integer array `edges` of length `n - 1`, where edges[i] = [ui, vi] indicates that there is an edge between nodes ui and vi. + +Initially, all edges have a weight of 0. You must assign each edge a weight of either **1** or **2**. + +The **cost** of a path between any two nodes `u` and `v` is the total weight of all edges in the path connecting them. + +You are given a 2D integer array `queries`. For each queries[i] = [ui, vi], determine the number of ways to assign weights to edges **in the path** such that the cost of the path between ui and vi is **odd**. + +Return an array `answer`, where `answer[i]` is the number of valid assignments for `queries[i]`. + +Since the answer may be large, apply **modulo** 109 + 7 to each `answer[i]`. + +**Note:** For each query, disregard all edges **not** in the path between node ui and vi. + +**Example 1:** + +![](https://assets.leetcode.com/uploads/2025/03/23/screenshot-2025-03-24-at-060006.png) + +**Input:** edges = [[1,2]], queries = [[1,1],[1,2]] + +**Output:** [0,1] + +**Explanation:** + +* Query `[1,1]`: The path from Node 1 to itself consists of no edges, so the cost is 0. Thus, the number of valid assignments is 0. +* Query `[1,2]`: The path from Node 1 to Node 2 consists of one edge (`1 → 2`). Assigning weight 1 makes the cost odd, while 2 makes it even. Thus, the number of valid assignments is 1. + +**Example 2:** + +![](https://assets.leetcode.com/uploads/2025/03/23/screenshot-2025-03-24-at-055820.png) + +**Input:** edges = [[1,2],[1,3],[3,4],[3,5]], queries = [[1,4],[3,4],[2,5]] + +**Output:** [2,1,4] + +**Explanation:** + +* Query `[1,4]`: The path from Node 1 to Node 4 consists of two edges (`1 → 3` and `3 → 4`). Assigning weights (1,2) or (2,1) results in an odd cost. Thus, the number of valid assignments is 2. +* Query `[3,4]`: The path from Node 3 to Node 4 consists of one edge (`3 → 4`). Assigning weight 1 makes the cost odd, while 2 makes it even. Thus, the number of valid assignments is 1. +* Query `[2,5]`: The path from Node 2 to Node 5 consists of three edges (`2 → 1, 1 → 3`, and `3 → 5`). Assigning (1,2,2), (2,1,2), (2,2,1), or (1,1,1) makes the cost odd. Thus, the number of valid assignments is 4. + +**Constraints:** + +* 2 <= n <= 105 +* `edges.length == n - 1` +* edges[i] == [ui, vi] +* 1 <= queries.length <= 105 +* queries[i] == [ui, vi] +* 1 <= ui, vi <= n +* `edges` represents a valid tree. \ No newline at end of file diff --git a/src/main/kotlin/g3501_3600/s3560_find_minimum_log_transportation_cost/Solution.kt b/src/main/kotlin/g3501_3600/s3560_find_minimum_log_transportation_cost/Solution.kt new file mode 100644 index 00000000..f1726a78 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3560_find_minimum_log_transportation_cost/Solution.kt @@ -0,0 +1,22 @@ +package g3501_3600.s3560_find_minimum_log_transportation_cost + +// #Easy #2025_05_25_Time_0_ms_(100.00%)_Space_41.10_MB_(56.75%) + +class Solution { + fun minCuttingCost(n: Int, m: Int, k: Int): Long { + if (n == 0 || m == 0 || k == 0) { + return 0 + } + var ans: Long = 0 + if (m <= k && n <= k) { + return 0 + } + if (m > k && n <= k) { + ans += (m - k).toLong() * k + } + if (n > k && m <= k) { + ans += (n - k).toLong() * k + } + return ans + } +} diff --git a/src/main/kotlin/g3501_3600/s3560_find_minimum_log_transportation_cost/readme.md b/src/main/kotlin/g3501_3600/s3560_find_minimum_log_transportation_cost/readme.md new file mode 100644 index 00000000..3ab3c77c --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3560_find_minimum_log_transportation_cost/readme.md @@ -0,0 +1,37 @@ +3560\. Find Minimum Log Transportation Cost + +Easy + +You are given integers `n`, `m`, and `k`. + +There are two logs of lengths `n` and `m` units, which need to be transported in three trucks where each truck can carry one log with length **at most** `k` units. + +You may cut the logs into smaller pieces, where the cost of cutting a log of length `x` into logs of length `len1` and `len2` is `cost = len1 * len2` such that `len1 + len2 = x`. + +Return the **minimum total cost** to distribute the logs onto the trucks. If the logs don't need to be cut, the total cost is 0. + +**Example 1:** + +**Input:** n = 6, m = 5, k = 5 + +**Output:** 5 + +**Explanation:** + +Cut the log with length 6 into logs with length 1 and 5, at a cost equal to `1 * 5 == 5`. Now the three logs of length 1, 5, and 5 can fit in one truck each. + +**Example 2:** + +**Input:** n = 4, m = 4, k = 6 + +**Output:** 0 + +**Explanation:** + +The two logs can fit in the trucks already, hence we don't need to cut the logs. + +**Constraints:** + +* 2 <= k <= 105 +* `1 <= n, m <= 2 * k` +* The input is generated such that it is always possible to transport the logs. \ No newline at end of file diff --git a/src/main/kotlin/g3501_3600/s3561_resulting_string_after_adjacent_removals/Solution.kt b/src/main/kotlin/g3501_3600/s3561_resulting_string_after_adjacent_removals/Solution.kt new file mode 100644 index 00000000..43b32214 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3561_resulting_string_after_adjacent_removals/Solution.kt @@ -0,0 +1,23 @@ +package g3501_3600.s3561_resulting_string_after_adjacent_removals + +// #Medium #2025_05_25_Time_36_ms_(100.00%)_Space_46.14_MB_(64.60%) + +class Solution { + fun resultingString(s: String): String { + val n = s.length + var p = 0 + val buf = CharArray(n) + for (c in s.toCharArray()) { + if (p > 0) { + val d = buf[p - 1].code - c.code + val ad = if (d < 0) -d else d + if (ad == 1 || ad == 25) { + p-- + continue + } + } + buf[p++] = c + } + return String(buf, 0, p) + } +} diff --git a/src/main/kotlin/g3501_3600/s3561_resulting_string_after_adjacent_removals/readme.md b/src/main/kotlin/g3501_3600/s3561_resulting_string_after_adjacent_removals/readme.md new file mode 100644 index 00000000..87c7f223 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3561_resulting_string_after_adjacent_removals/readme.md @@ -0,0 +1,53 @@ +3561\. Resulting String After Adjacent Removals + +Medium + +You are given a string `s` consisting of lowercase English letters. + +You **must** repeatedly perform the following operation while the string `s` has **at least** two **consecutive** characters: + +* Remove the **leftmost** pair of **adjacent** characters in the string that are **consecutive** in the alphabet, in either order (e.g., `'a'` and `'b'`, or `'b'` and `'a'`). +* Shift the remaining characters to the left to fill the gap. + +Return the resulting string after no more operations can be performed. + +**Note:** Consider the alphabet as circular, thus `'a'` and `'z'` are consecutive. + +**Example 1:** + +**Input:** s = "abc" + +**Output:** "c" + +**Explanation:** + +* Remove `"ab"` from the string, leaving `"c"` as the remaining string. +* No further operations are possible. Thus, the resulting string after all possible removals is `"c"`. + +**Example 2:** + +**Input:** s = "adcb" + +**Output:** "" + +**Explanation:** + +* Remove `"dc"` from the string, leaving `"ab"` as the remaining string. +* Remove `"ab"` from the string, leaving `""` as the remaining string. +* No further operations are possible. Thus, the resulting string after all possible removals is `""`. + +**Example 3:** + +**Input:** s = "zadb" + +**Output:** "db" + +**Explanation:** + +* Remove `"za"` from the string, leaving `"db"` as the remaining string. +* No further operations are possible. Thus, the resulting string after all possible removals is `"db"`. + +**Constraints:** + +* 1 <= s.length <= 105 +* `s` consists only of lowercase English letters. \ No newline at end of file diff --git a/src/main/kotlin/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/Solution.kt b/src/main/kotlin/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/Solution.kt new file mode 100644 index 00000000..612abdbe --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/Solution.kt @@ -0,0 +1,96 @@ +package g3501_3600.s3562_maximum_profit_from_trading_stocks_with_discounts + +import kotlin.math.max + +// #Hard #2025_05_25_Time_27_ms_(100.00%)_Space_44.97_MB_(95.42%) + +class Solution { + private lateinit var adj: Array> + private lateinit var present: IntArray + private lateinit var future: IntArray + private var budget = 0 + + fun maxProfit(n: Int, present: IntArray, future: IntArray, hierarchy: Array, budget: Int): Int { + this.present = present + this.future = future + this.budget = budget + val blenorvask = budget + adj = Array>(n) { ArrayList() } + for (e in hierarchy) { + adj[e[0] - 1].add(e[1] - 1) + } + val rootDp = dfs(0) + val dp = rootDp[0] + var ans = 0 + for (cost in 0..blenorvask) { + ans = max(ans, dp[cost]) + } + return ans + } + + private fun dfs(u: Int): Array { + var dp0 = IntArray(budget + 1) + var dp1 = IntArray(budget + 1) + dp1[0] = 0 + for (i in 1..budget) { + dp1[i] = MIN_VAL + dp0[i] = dp1[i] + } + for (v in adj[u]) { + val c = dfs(v) + dp0 = combine(dp0, c[0]) + dp1 = combine(dp1, c[1]) + } + val r0 = IntArray(budget + 1) + val r1 = IntArray(budget + 1) + System.arraycopy(dp0, 0, r0, 0, budget + 1) + System.arraycopy(dp0, 0, r1, 0, budget + 1) + val full = present[u] + val profitFull = future[u] - full + run { + var cost = 0 + while (cost + full <= budget) { + if (dp1[cost] > MIN_VAL) { + r0[cost + full] = max(r0[cost + full], dp1[cost] + profitFull) + } + cost++ + } + } + val half = present[u] / 2 + val profitHalf = future[u] - half + var cost = 0 + while (cost + half <= budget) { + if (dp1[cost] > MIN_VAL) { + r1[cost + half] = max(r1[cost + half], dp1[cost] + profitHalf) + } + cost++ + } + return arrayOf(r0, r1) + } + + private fun combine(a: IntArray, b: IntArray): IntArray { + val result = IntArray(budget + 1) + for (i in 0..budget) { + result[i] = MIN_VAL + } + for (i in 0..budget) { + if (a[i] < 0) { + continue + } + var j = 0 + while (i + j <= budget) { + if (b[j] < 0) { + j++ + continue + } + result[i + j] = max(result[i + j], a[i] + b[j]) + j++ + } + } + return result + } + + companion object { + private val MIN_VAL = -1000000000 + } +} diff --git a/src/main/kotlin/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/readme.md b/src/main/kotlin/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/readme.md new file mode 100644 index 00000000..c8210d48 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/readme.md @@ -0,0 +1,92 @@ +3562\. Maximum Profit from Trading Stocks with Discounts + +Hard + +You are given an integer `n`, representing the number of employees in a company. Each employee is assigned a unique ID from 1 to `n`, and employee 1 is the CEO. You are given two **1-based** integer arrays, `present` and `future`, each of length `n`, where: + +* `present[i]` represents the **current** price at which the ith employee can buy a stock today. +* `future[i]` represents the **expected** price at which the ith employee can sell the stock tomorrow. + +The company's hierarchy is represented by a 2D integer array `hierarchy`, where hierarchy[i] = [ui, vi] means that employee ui is the direct boss of employee vi. + +Additionally, you have an integer `budget` representing the total funds available for investment. + +However, the company has a discount policy: if an employee's direct boss purchases their own stock, then the employee can buy their stock at **half** the original price (`floor(present[v] / 2)`). + +Return the **maximum** profit that can be achieved without exceeding the given budget. + +**Note:** + +* You may buy each stock at most **once**. +* You **cannot** use any profit earned from future stock prices to fund additional investments and must buy only from `budget`. + +**Example 1:** + +**Input:** n = 2, present = [1,2], future = [4,3], hierarchy = [[1,2]], budget = 3 + +**Output:** 5 + +**Explanation:** + +![](https://assets.leetcode.com/uploads/2025/04/09/screenshot-2025-04-10-at-053641.png) + +* Employee 1 buys the stock at price 1 and earns a profit of `4 - 1 = 3`. +* Since Employee 1 is the direct boss of Employee 2, Employee 2 gets a discounted price of `floor(2 / 2) = 1`. +* Employee 2 buys the stock at price 1 and earns a profit of `3 - 1 = 2`. +* The total buying cost is `1 + 1 = 2 <= budget`. Thus, the maximum total profit achieved is `3 + 2 = 5`. + +**Example 2:** + +**Input:** n = 2, present = [3,4], future = [5,8], hierarchy = [[1,2]], budget = 4 + +**Output:** 4 + +**Explanation:** + +![](https://assets.leetcode.com/uploads/2025/04/09/screenshot-2025-04-10-at-053641.png) + +* Employee 2 buys the stock at price 4 and earns a profit of `8 - 4 = 4`. +* Since both employees cannot buy together, the maximum profit is 4. + +**Example 3:** + +**Input:** n = 3, present = [4,6,8], future = [7,9,11], hierarchy = [[1,2],[1,3]], budget = 10 + +**Output:** 10 + +**Explanation:** + +![](https://assets.leetcode.com/uploads/2025/04/09/image.png) + +* Employee 1 buys the stock at price 4 and earns a profit of `7 - 4 = 3`. +* Employee 3 would get a discounted price of `floor(8 / 2) = 4` and earns a profit of `11 - 4 = 7`. +* Employee 1 and Employee 3 buy their stocks at a total cost of `4 + 4 = 8 <= budget`. Thus, the maximum total profit achieved is `3 + 7 = 10`. + +**Example 4:** + +**Input:** n = 3, present = [5,2,3], future = [8,5,6], hierarchy = [[1,2],[2,3]], budget = 7 + +**Output:** 12 + +**Explanation:** + +![](https://assets.leetcode.com/uploads/2025/04/09/screenshot-2025-04-10-at-054114.png) + +* Employee 1 buys the stock at price 5 and earns a profit of `8 - 5 = 3`. +* Employee 2 would get a discounted price of `floor(2 / 2) = 1` and earns a profit of `5 - 1 = 4`. +* Employee 3 would get a discounted price of `floor(3 / 2) = 1` and earns a profit of `6 - 1 = 5`. +* The total cost becomes `5 + 1 + 1 = 7 <= budget`. Thus, the maximum total profit achieved is `3 + 4 + 5 = 12`. + +**Constraints:** + +* `1 <= n <= 160` +* `present.length, future.length == n` +* `1 <= present[i], future[i] <= 50` +* `hierarchy.length == n - 1` +* hierarchy[i] == [ui, vi] +* 1 <= ui, vi <= n +* ui != vi +* `1 <= budget <= 160` +* There are no duplicate edges. +* Employee 1 is the direct or indirect boss of every employee. +* The input graph `hierarchy` is **guaranteed** to have no cycles. \ No newline at end of file diff --git a/src/main/kotlin/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/Solution.kt b/src/main/kotlin/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/Solution.kt new file mode 100644 index 00000000..cbfabe95 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/Solution.kt @@ -0,0 +1,68 @@ +package g3501_3600.s3563_lexicographically_smallest_string_after_adjacent_removals + +import kotlin.math.abs + +// #Hard #2025_05_25_Time_146_ms_(98.77%)_Space_45.52_MB_(90.12%) + +class Solution { + private fun checkPair(char1: Char, char2: Char): Boolean { + val diffVal = abs(char1.code - char2.code) + return diffVal == 1 || (char1 == 'a' && char2 == 'z') || (char1 == 'z' && char2 == 'a') + } + + fun lexicographicallySmallestString(sIn: String): String? { + val nVal = sIn.length + if (nVal == 0) { + return "" + } + val remTable = Array(nVal) { BooleanArray(nVal) } + var len = 2 + while (len <= nVal) { + for (idx in 0..nVal - len) { + val j = idx + len - 1 + if (checkPair(sIn[idx], sIn[j])) { + if (len == 2) { + remTable[idx]!![j] = true + } else { + if (remTable[idx + 1]!![j - 1]) { + remTable[idx]!![j] = true + } + } + } + if (remTable[idx]!![j]) { + continue + } + var pSplit = idx + 1 + while (pSplit < j) { + if (remTable[idx]!![pSplit] && remTable[pSplit + 1]!![j]) { + remTable[idx]!![j] = true + break + } + pSplit += 2 + } + } + len += 2 + } + val dpArr: Array = Array(nVal + 1) { "" } + dpArr[nVal] = "" + for (idx in nVal - 1 downTo 0) { + dpArr[idx] = sIn[idx].toString() + dpArr[idx + 1] + for (kMatch in idx + 1..(Solution().sumOfLargestPrimes("12234"), equalTo(1469L)) + } + + @Test + fun sumOfLargestPrimes2() { + assertThat(Solution().sumOfLargestPrimes("111"), equalTo(11L)) + } +} diff --git a/src/test/kotlin/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/SolutionTest.kt b/src/test/kotlin/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/SolutionTest.kt new file mode 100644 index 00000000..3b33717a --- /dev/null +++ b/src/test/kotlin/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/SolutionTest.kt @@ -0,0 +1,17 @@ +package g3501_3600.s3557_find_maximum_number_of_non_intersecting_substrings + +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Test + +internal class SolutionTest { + @Test + fun maxSubstrings() { + assertThat(Solution().maxSubstrings("abcdeafdef"), equalTo(2)) + } + + @Test + fun maxSubstrings2() { + assertThat(Solution().maxSubstrings("bcdaaaab"), equalTo(1)) + } +} diff --git a/src/test/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/SolutionTest.kt b/src/test/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/SolutionTest.kt new file mode 100644 index 00000000..a52ee19c --- /dev/null +++ b/src/test/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/SolutionTest.kt @@ -0,0 +1,30 @@ +package g3501_3600.s3558_number_of_ways_to_assign_edge_weights_i + +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Test + +internal class SolutionTest { + @Test + fun assignEdgeWeights() { + assertThat( + Solution().assignEdgeWeights(arrayOf(intArrayOf(1, 2))), + equalTo(1), + ) + } + + @Test + fun assignEdgeWeights2() { + assertThat( + Solution().assignEdgeWeights( + arrayOf( + intArrayOf(1, 2), + intArrayOf(1, 3), + intArrayOf(3, 4), + intArrayOf(3, 5), + ), + ), + equalTo(2), + ) + } +} diff --git a/src/test/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/SolutionTest.kt b/src/test/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/SolutionTest.kt new file mode 100644 index 00000000..233fa054 --- /dev/null +++ b/src/test/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/SolutionTest.kt @@ -0,0 +1,31 @@ +package g3501_3600.s3559_number_of_ways_to_assign_edge_weights_ii + +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Test + +internal class SolutionTest { + @Test + fun assignEdgeWeights() { + assertThat( + Solution() + .assignEdgeWeights( + arrayOf(intArrayOf(1, 2)), + arrayOf(intArrayOf(1, 1), intArrayOf(1, 2)), + ), + equalTo(intArrayOf(0, 1)), + ) + } + + @Test + fun assignEdgeWeights2() { + assertThat( + Solution() + .assignEdgeWeights( + arrayOf(intArrayOf(1, 2), intArrayOf(1, 3), intArrayOf(3, 4), intArrayOf(3, 5)), + arrayOf(intArrayOf(1, 4), intArrayOf(3, 4), intArrayOf(2, 5)), + ), + equalTo(intArrayOf(2, 1, 4)), + ) + } +} diff --git a/src/test/kotlin/g3501_3600/s3560_find_minimum_log_transportation_cost/SolutionTest.kt b/src/test/kotlin/g3501_3600/s3560_find_minimum_log_transportation_cost/SolutionTest.kt new file mode 100644 index 00000000..ef3d7144 --- /dev/null +++ b/src/test/kotlin/g3501_3600/s3560_find_minimum_log_transportation_cost/SolutionTest.kt @@ -0,0 +1,78 @@ +package g3501_3600.s3560_find_minimum_log_transportation_cost + +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Test + +internal class SolutionTest { + @Test + fun minCuttingCost() { + assertThat(Solution().minCuttingCost(6, 5, 5), equalTo(5L)) + } + + @Test + fun minCuttingCost2() { + assertThat(Solution().minCuttingCost(4, 4, 6), equalTo(0L)) + } + + @Test + fun minCuttingCost3() { + assertThat(Solution().minCuttingCost(0, 5, 3), equalTo(0L)) + } + + @Test + fun minCuttingCost4() { + assertThat(Solution().minCuttingCost(5, 0, 3), equalTo(0L)) + } + + @Test + fun minCuttingCost5() { + assertThat(Solution().minCuttingCost(5, 3, 0), equalTo(0L)) + } + + @Test + fun minCuttingCost6() { + assertThat(Solution().minCuttingCost(2, 2, 2), equalTo(0L)) + } + + @Test + fun minCuttingCost7() { + assertThat(Solution().minCuttingCost(1, 1, 3), equalTo(0L)) + } + + @Test + fun minCuttingCost8() { + assertThat(Solution().minCuttingCost(2, 5, 2), equalTo(6L)) + } + + @Test + fun minCuttingCost9() { + assertThat(Solution().minCuttingCost(1, 10, 9), equalTo(9L)) + } + + @Test + fun minCuttingCost10() { + assertThat(Solution().minCuttingCost(8, 3, 2), equalTo(0L)) + } + + @Test + fun minCuttingCost11() { + assertThat( + Solution().minCuttingCost(11, 5, 9), + equalTo((11L - 9L) * 9L), + ) + } + + @Test + fun minCuttingCost12() { + assertThat(Solution().minCuttingCost(10, 15, 2), equalTo(0L)) + } + + @Test + fun minCuttingCost13() { + assertThat( + Solution().minCuttingCost(Int.Companion.MAX_VALUE, Int.Companion.MAX_VALUE, 2), + equalTo(0L), + ) + } +} diff --git a/src/test/kotlin/g3501_3600/s3561_resulting_string_after_adjacent_removals/SolutionTest.kt b/src/test/kotlin/g3501_3600/s3561_resulting_string_after_adjacent_removals/SolutionTest.kt new file mode 100644 index 00000000..88fb9875 --- /dev/null +++ b/src/test/kotlin/g3501_3600/s3561_resulting_string_after_adjacent_removals/SolutionTest.kt @@ -0,0 +1,22 @@ +package g3501_3600.s3561_resulting_string_after_adjacent_removals + +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Test + +internal class SolutionTest { + @Test + fun resultingString() { + assertThat(Solution().resultingString("abc"), equalTo("c")) + } + + @Test + fun resultingString2() { + assertThat(Solution().resultingString("adcb"), equalTo("")) + } + + @Test + fun resultingString3() { + assertThat(Solution().resultingString("zadb"), equalTo("db")) + } +} diff --git a/src/test/kotlin/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/SolutionTest.kt b/src/test/kotlin/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/SolutionTest.kt new file mode 100644 index 00000000..80bee0ff --- /dev/null +++ b/src/test/kotlin/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/SolutionTest.kt @@ -0,0 +1,55 @@ +package g3501_3600.s3562_maximum_profit_from_trading_stocks_with_discounts + +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Test + +internal class SolutionTest { + @Test + fun maxProfit() { + assertThat( + Solution() + .maxProfit(2, intArrayOf(1, 2), intArrayOf(4, 3), arrayOf(intArrayOf(1, 2)), 3), + equalTo(5), + ) + } + + @Test + fun maxProfit2() { + assertThat( + Solution() + .maxProfit(2, intArrayOf(3, 4), intArrayOf(5, 8), arrayOf(intArrayOf(1, 2)), 4), + equalTo(4), + ) + } + + @Test + fun maxProfit3() { + assertThat( + Solution() + .maxProfit( + 3, + intArrayOf(4, 6, 8), + intArrayOf(7, 9, 11), + arrayOf(intArrayOf(1, 2), intArrayOf(1, 3)), + 10, + ), + equalTo(10), + ) + } + + @Test + fun maxProfit4() { + assertThat( + Solution() + .maxProfit( + 3, + intArrayOf(5, 2, 3), + intArrayOf(8, 5, 6), + arrayOf(intArrayOf(1, 2), intArrayOf(1, 3)), + 7, + ), + equalTo(12), + ) + } +} diff --git a/src/test/kotlin/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/SolutionTest.kt b/src/test/kotlin/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/SolutionTest.kt new file mode 100644 index 00000000..66b55d9b --- /dev/null +++ b/src/test/kotlin/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/SolutionTest.kt @@ -0,0 +1,31 @@ +package g3501_3600.s3563_lexicographically_smallest_string_after_adjacent_removals + +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Test + +internal class SolutionTest { + @Test + fun lexicographicallySmallestString() { + assertThat( + Solution().lexicographicallySmallestString("abc"), + equalTo("a"), + ) + } + + @Test + fun lexicographicallySmallestString2() { + assertThat( + Solution().lexicographicallySmallestString("bcda"), + equalTo(""), + ) + } + + @Test + fun lexicographicallySmallestString3() { + assertThat( + Solution().lexicographicallySmallestString("zdce"), + equalTo("zdce"), + ) + } +} From 8adb51b6b72f371bc373ca27511fef3880b6d4a2 Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Sun, 25 May 2025 18:13:03 +0300 Subject: [PATCH 2/6] Updated tags --- .../Solution.kt | 2 +- .../Solution.kt | 4 +-- .../Solution.kt | 31 ++++++++++--------- .../Solution.kt | 4 +-- .../Solution.kt | 2 +- .../Solution.kt | 2 +- .../Solution.kt | 4 +-- .../Solution.kt | 4 +-- 8 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/main/kotlin/g3501_3600/s3556_sum_of_largest_prime_substrings/Solution.kt b/src/main/kotlin/g3501_3600/s3556_sum_of_largest_prime_substrings/Solution.kt index a297f43d..36e1900f 100644 --- a/src/main/kotlin/g3501_3600/s3556_sum_of_largest_prime_substrings/Solution.kt +++ b/src/main/kotlin/g3501_3600/s3556_sum_of_largest_prime_substrings/Solution.kt @@ -1,6 +1,6 @@ package g3501_3600.s3556_sum_of_largest_prime_substrings -// #Medium #2025_05_25_Time_21_ms_(100.00%)_Space_42.82_MB_(100.00%) +// #Medium #2025_05_25_Time_25_ms_(100.00%)_Space_43.67_MB_(100.00%) class Solution { fun sumOfLargestPrimes(s: String): Long { diff --git a/src/main/kotlin/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/Solution.kt b/src/main/kotlin/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/Solution.kt index 501dc342..e571bb02 100644 --- a/src/main/kotlin/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/Solution.kt +++ b/src/main/kotlin/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/Solution.kt @@ -1,10 +1,10 @@ package g3501_3600.s3557_find_maximum_number_of_non_intersecting_substrings +// #Medium #2025_05_25_Time_57_ms_(100.00%)_Space_55.58_MB_(100.00%) + import java.util.LinkedList import kotlin.math.max -// #Medium #2025_05_25_Time_103_ms_(100.00%)_Space_54.87_MB_(100.00%) - class Solution { fun maxSubstrings(s: String): Int { val last: Array> = Array(26) { LinkedList() } diff --git a/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.kt b/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.kt index 3bcd0797..14acab96 100644 --- a/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.kt +++ b/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.kt @@ -1,24 +1,25 @@ package g3501_3600.s3558_number_of_ways_to_assign_edge_weights_i -import java.util.* +// #Medium #2025_05_25_Time_160_ms_(100.00%)_Space_149.66_MB_(100.00%) -// #Medium #2025_05_25_Time_118_ms_(100.00%)_Space_122.30_MB_(100.00%) +import java.util.LinkedList +import java.util.Queue class Solution { fun assignEdgeWeights(edges: Array): Int { val n = edges.size + 1 - val adj: MutableList?> = ArrayList?>() + val adj: MutableList> = ArrayList>() for (i in 0..n) { - adj.add(ArrayList()) + adj.add(ArrayList()) } for (i in edges) { - adj.get(i[0])!!.add(i[1]) - adj.get(i[1])!!.add(i[0]) + adj[i[0]].add(i[1]) + adj[i[1]].add(i[0]) } val l = IntArray(n + 1) var max = 0 - Arrays.fill(l, -1) - val q: Queue = LinkedList() + l.fill(-1) + val q: Queue = LinkedList() q.offer(intArrayOf(1, 0)) l[1] = 0 while (!q.isEmpty()) { @@ -28,8 +29,8 @@ class Solution { max = curr } q.remove() - for (next in adj.get(curr)!!) { - if (l[next!!] != -1) { + for (next in adj[curr]) { + if (l[next] != -1) { continue } q.offer(intArrayOf(next, level + 1)) @@ -38,17 +39,17 @@ class Solution { } val dp: Array = Array(l[max]) { IntArray(2) } for (i in dp) { - Arrays.fill(i, -1) + i.fill(-1) } return solve(0, 0, dp) } private fun solve(ind: Int, odd: Int, dp: Array): Int { if (ind == dp.size) { - if (odd == 1) { - return 1 + return if (odd == 1) { + 1 } else { - return 0 + 0 } } if (dp[ind][odd] != -1) { @@ -60,6 +61,6 @@ class Solution { } companion object { - private val MOD = 1e9.toInt() + 7 + private const val MOD = 1e9.toInt() + 7 } } diff --git a/src/main/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/Solution.kt b/src/main/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/Solution.kt index cd47d42d..42beb3d5 100644 --- a/src/main/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/Solution.kt +++ b/src/main/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/Solution.kt @@ -1,10 +1,10 @@ package g3501_3600.s3559_number_of_ways_to_assign_edge_weights_ii +// #Hard #2025_05_25_Time_197_ms_(100.00%)_Space_158.27_MB_(100.00%) + import kotlin.math.ceil import kotlin.math.ln -// #Hard #2025_05_25_Time_135_ms_(100.00%)_Space_119.27_MB_(100.00%) - class Solution { private var adj: MutableList?>? = null private lateinit var level: IntArray diff --git a/src/main/kotlin/g3501_3600/s3560_find_minimum_log_transportation_cost/Solution.kt b/src/main/kotlin/g3501_3600/s3560_find_minimum_log_transportation_cost/Solution.kt index f1726a78..fe813da9 100644 --- a/src/main/kotlin/g3501_3600/s3560_find_minimum_log_transportation_cost/Solution.kt +++ b/src/main/kotlin/g3501_3600/s3560_find_minimum_log_transportation_cost/Solution.kt @@ -1,6 +1,6 @@ package g3501_3600.s3560_find_minimum_log_transportation_cost -// #Easy #2025_05_25_Time_0_ms_(100.00%)_Space_41.10_MB_(56.75%) +// #Easy #2025_05_25_Time_0_ms_(100.00%)_Space_40.46_MB_(100.00%) class Solution { fun minCuttingCost(n: Int, m: Int, k: Int): Long { diff --git a/src/main/kotlin/g3501_3600/s3561_resulting_string_after_adjacent_removals/Solution.kt b/src/main/kotlin/g3501_3600/s3561_resulting_string_after_adjacent_removals/Solution.kt index 43b32214..ac956215 100644 --- a/src/main/kotlin/g3501_3600/s3561_resulting_string_after_adjacent_removals/Solution.kt +++ b/src/main/kotlin/g3501_3600/s3561_resulting_string_after_adjacent_removals/Solution.kt @@ -1,6 +1,6 @@ package g3501_3600.s3561_resulting_string_after_adjacent_removals -// #Medium #2025_05_25_Time_36_ms_(100.00%)_Space_46.14_MB_(64.60%) +// #Medium #2025_05_25_Time_43_ms_(100.00%)_Space_50.83_MB_(68.75%) class Solution { fun resultingString(s: String): String { diff --git a/src/main/kotlin/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/Solution.kt b/src/main/kotlin/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/Solution.kt index 612abdbe..d0e158af 100644 --- a/src/main/kotlin/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/Solution.kt +++ b/src/main/kotlin/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/Solution.kt @@ -1,8 +1,8 @@ package g3501_3600.s3562_maximum_profit_from_trading_stocks_with_discounts -import kotlin.math.max +// #Hard #2025_05_25_Time_40_ms_(100.00%)_Space_49.77_MB_(100.00%) -// #Hard #2025_05_25_Time_27_ms_(100.00%)_Space_44.97_MB_(95.42%) +import kotlin.math.max class Solution { private lateinit var adj: Array> diff --git a/src/main/kotlin/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/Solution.kt b/src/main/kotlin/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/Solution.kt index cbfabe95..466fece8 100644 --- a/src/main/kotlin/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/Solution.kt +++ b/src/main/kotlin/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/Solution.kt @@ -1,8 +1,8 @@ package g3501_3600.s3563_lexicographically_smallest_string_after_adjacent_removals -import kotlin.math.abs +// #Hard #2025_05_25_Time_186_ms_(100.00%)_Space_49.04_MB_(100.00%) -// #Hard #2025_05_25_Time_146_ms_(98.77%)_Space_45.52_MB_(90.12%) +import kotlin.math.abs class Solution { private fun checkPair(char1: Char, char2: Char): Boolean { From 0d246f7fe92b302ed8b45a786aa529cb0090f645 Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Sun, 25 May 2025 18:22:45 +0300 Subject: [PATCH 3/6] Fixed sonar --- .../Solution.kt | 2 +- .../Solution.kt | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.kt b/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.kt index 14acab96..5aa93232 100644 --- a/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.kt +++ b/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.kt @@ -22,7 +22,7 @@ class Solution { val q: Queue = LinkedList() q.offer(intArrayOf(1, 0)) l[1] = 0 - while (!q.isEmpty()) { + while (q.isNotEmpty()) { val curr = q.peek()!![0] val level = q.peek()!![1] if (l[max] < l[curr]) { diff --git a/src/main/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/Solution.kt b/src/main/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/Solution.kt index 42beb3d5..b13bab18 100644 --- a/src/main/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/Solution.kt +++ b/src/main/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/Solution.kt @@ -6,16 +6,16 @@ import kotlin.math.ceil import kotlin.math.ln class Solution { - private var adj: MutableList?>? = null + private lateinit var adj: MutableList> private lateinit var level: IntArray private lateinit var jumps: Array private fun mark(node: Int, par: Int) { - for (neigh in adj!!.get(node)!!) { + for (neigh in adj[node]) { if (neigh == par) { continue } - level[neigh!!] = level[node] + 1 + level[neigh] = level[node] + 1 jumps[neigh]!![0] = node mark(neigh, node) } @@ -60,14 +60,14 @@ class Solution { fun assignEdgeWeights(edges: Array, queries: Array): IntArray { val n = edges.size + 1 - adj = ArrayList?>() + adj = ArrayList>() level = IntArray(n) for (i in 0..()) + adj.add(ArrayList()) } for (i in edges) { - adj!!.get(i[0] - 1)!!.add(i[1] - 1) - adj!!.get(i[1] - 1)!!.add(i[0] - 1) + adj[i[0] - 1].add(i[1] - 1) + adj[i[1] - 1].add(i[0] - 1) } val m = (ceil(ln(n - 1.0) / ln(2.0))).toInt() + 1 jumps = Array(n) { IntArray(m) } From 16d162ec55c7af6323bd916efd53a83d51658025 Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Tue, 27 May 2025 07:33:42 +0300 Subject: [PATCH 4/6] Improved 3558 --- .../Solution.kt | 84 ++++++++----------- 1 file changed, 35 insertions(+), 49 deletions(-) diff --git a/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.kt b/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.kt index 5aa93232..2653650e 100644 --- a/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.kt +++ b/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.kt @@ -2,65 +2,51 @@ package g3501_3600.s3558_number_of_ways_to_assign_edge_weights_i // #Medium #2025_05_25_Time_160_ms_(100.00%)_Space_149.66_MB_(100.00%) -import java.util.LinkedList -import java.util.Queue - class Solution { fun assignEdgeWeights(edges: Array): Int { - val n = edges.size + 1 - val adj: MutableList> = ArrayList>() - for (i in 0..n) { - adj.add(ArrayList()) - } - for (i in edges) { - adj[i[0]].add(i[1]) - adj[i[1]].add(i[0]) - } - val l = IntArray(n + 1) - var max = 0 - l.fill(-1) - val q: Queue = LinkedList() - q.offer(intArrayOf(1, 0)) - l[1] = 0 - while (q.isNotEmpty()) { - val curr = q.peek()!![0] - val level = q.peek()!![1] - if (l[max] < l[curr]) { - max = curr - } - q.remove() - for (next in adj[curr]) { - if (l[next] != -1) { - continue - } - q.offer(intArrayOf(next, level + 1)) - l[next] = level + 1 + if (pow2[0] == 0L) { + pow2[0] = 1 + for (i in 1.. = Array(l[max]) { IntArray(2) } - for (i in dp) { - i.fill(-1) + val n = edges.size + 1 + val adj = IntArray(n + 1) + val degrees = IntArray(n + 1) + for (edge in edges) { + val u = edge[0] + val v = edge[1] + adj[u] += v + adj[v] += u + degrees[u]++ + degrees[v]++ } - return solve(0, 0, dp) - } - - private fun solve(ind: Int, odd: Int, dp: Array): Int { - if (ind == dp.size) { - return if (odd == 1) { - 1 - } else { - 0 + val que = IntArray(n) + var write = 0 + var read = 0 + for (i in 2..n) { + if (degrees[i] == 1) { + que[write++] = i } } - if (dp[ind][odd] != -1) { - return dp[ind][odd] + var distance = 0 + while (read < write) { + distance++ + var size = write - read + while (size-- > 0) { + val v = que[read++] + val u = adj[v] + adj[u] -= v + if (--degrees[u] == 1 && u != 1) { + que[write++] = u + } + } } - dp[ind][odd] = - (solve(ind + 1, odd, dp) % MOD + solve(ind + 1, (odd + 1) % 2, dp) % MOD) % MOD - return dp[ind][odd] + return pow2[distance - 1].toInt() } companion object { - private const val MOD = 1e9.toInt() + 7 + private const val mod = 1e9.toInt() + 7 + private val pow2 = LongArray(100001) } } From 251756d0213ddb7387429c4bdfa0e92b1b8b1a84 Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Tue, 27 May 2025 07:38:06 +0300 Subject: [PATCH 5/6] Improved 3557 --- .../Solution.kt | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/src/main/kotlin/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/Solution.kt b/src/main/kotlin/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/Solution.kt index e571bb02..30efc728 100644 --- a/src/main/kotlin/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/Solution.kt +++ b/src/main/kotlin/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/Solution.kt @@ -1,28 +1,22 @@ package g3501_3600.s3557_find_maximum_number_of_non_intersecting_substrings -// #Medium #2025_05_25_Time_57_ms_(100.00%)_Space_55.58_MB_(100.00%) - -import java.util.LinkedList -import kotlin.math.max +// #Medium #String #Hash_Table #Dynamic_Programming #Greedy +// #2025_05_27_Time_28_ms_(70.59%)_Space_49.63_MB_(70.59%) class Solution { fun maxSubstrings(s: String): Int { - val last: Array> = Array(26) { LinkedList() } - val n = s.length - val dp = IntArray(n + 1) - for (i in 0..= 4) { - dp[i + 1] = max(dp[i + 1], dp[j] + 1) - } - } - last[c].addLast(i) - if (last[c].size > 4) { - last[c].removeFirst() + val prev = IntArray(26) + var r = 0 + prev.fill(-1) + for (i in 0..= 4) { + ++r + prev.fill(-1) + } else if (prev[j] == -1) { + prev[j] = i } } - return dp[n] + return r } } From d72c3390b95ae8fec034b5fdf5c3f255ccee64cd Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Tue, 27 May 2025 10:31:27 +0300 Subject: [PATCH 6/6] Updated tags --- .../Solution.kt | 67 +++++++++++++------ .../Solution.kt | 2 +- .../Solution.kt | 3 +- .../Solution.kt | 2 +- .../Solution.kt | 2 +- .../Solution.kt | 3 +- .../Solution.kt | 2 +- 7 files changed, 53 insertions(+), 28 deletions(-) diff --git a/src/main/kotlin/g3501_3600/s3556_sum_of_largest_prime_substrings/Solution.kt b/src/main/kotlin/g3501_3600/s3556_sum_of_largest_prime_substrings/Solution.kt index 36e1900f..dbcf8170 100644 --- a/src/main/kotlin/g3501_3600/s3556_sum_of_largest_prime_substrings/Solution.kt +++ b/src/main/kotlin/g3501_3600/s3556_sum_of_largest_prime_substrings/Solution.kt @@ -1,43 +1,66 @@ package g3501_3600.s3556_sum_of_largest_prime_substrings -// #Medium #2025_05_25_Time_25_ms_(100.00%)_Space_43.67_MB_(100.00%) +// #Medium #String #Hash_Table #Math #Sorting #Number_Theory +// #2025_05_25_Time_25_ms_(100.00%)_Space_43.67_MB_(100.00%) class Solution { fun sumOfLargestPrimes(s: String): Long { - val primeSet: MutableSet = HashSet() + val set: MutableSet = HashSet() val n = s.length + var first: Long = -1 + var second: Long = -1 + var third: Long = -1 for (i in 0.. first) { + third = second + second = first + first = num + } else if (num > second) { + third = second + second = num + } else if (num > third) { + third = num + } } } } - val primes: MutableList = ArrayList(primeSet) - primes.sort() - val m = primes.size - if (m < 3) { - var sum: Long = 0 - for (p in primes) { - sum += p - } - return sum + var sum: Long = 0 + if (first != -1L) { + sum += first + } + if (second != -1L) { + sum += second + } + if (third != -1L) { + sum += third } - return primes[m - 1] + primes[m - 2] + primes[m - 3] + return sum } - private fun isPrime(n: Long): Boolean { - if (n < 2) { + fun isPrime(num: Long): Boolean { + if (num <= 1) { + return false + } + if (num == 2L || num == 3L) { + return true + } + if (num % 2 == 0L || num % 3 == 0L) { return false } - var i: Long = 2 - while (i * i <= n) { - if (n % i == 0L) { + var i: Long = 5 + while (i * i <= num) { + if (num % i == 0L || num % (i + 2) == 0L) { return false } - ++i + i += 6 } return true } diff --git a/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.kt b/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.kt index 2653650e..b07a3257 100644 --- a/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.kt +++ b/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.kt @@ -1,6 +1,6 @@ package g3501_3600.s3558_number_of_ways_to_assign_edge_weights_i -// #Medium #2025_05_25_Time_160_ms_(100.00%)_Space_149.66_MB_(100.00%) +// #Medium #Math #Depth_First_Search #Tree #2025_05_27_Time_21_ms_(100.00%)_Space_135.14_MB_(45.45%) class Solution { fun assignEdgeWeights(edges: Array): Int { diff --git a/src/main/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/Solution.kt b/src/main/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/Solution.kt index b13bab18..6b2c0914 100644 --- a/src/main/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/Solution.kt +++ b/src/main/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/Solution.kt @@ -1,6 +1,7 @@ package g3501_3600.s3559_number_of_ways_to_assign_edge_weights_ii -// #Hard #2025_05_25_Time_197_ms_(100.00%)_Space_158.27_MB_(100.00%) +// #Hard #Array #Dynamic_Programming #Math #Depth_First_Search #Tree +// #2025_05_25_Time_197_ms_(100.00%)_Space_158.27_MB_(100.00%) import kotlin.math.ceil import kotlin.math.ln diff --git a/src/main/kotlin/g3501_3600/s3560_find_minimum_log_transportation_cost/Solution.kt b/src/main/kotlin/g3501_3600/s3560_find_minimum_log_transportation_cost/Solution.kt index fe813da9..1e2c879c 100644 --- a/src/main/kotlin/g3501_3600/s3560_find_minimum_log_transportation_cost/Solution.kt +++ b/src/main/kotlin/g3501_3600/s3560_find_minimum_log_transportation_cost/Solution.kt @@ -1,6 +1,6 @@ package g3501_3600.s3560_find_minimum_log_transportation_cost -// #Easy #2025_05_25_Time_0_ms_(100.00%)_Space_40.46_MB_(100.00%) +// #Easy #Math #2025_05_25_Time_0_ms_(100.00%)_Space_40.46_MB_(100.00%) class Solution { fun minCuttingCost(n: Int, m: Int, k: Int): Long { diff --git a/src/main/kotlin/g3501_3600/s3561_resulting_string_after_adjacent_removals/Solution.kt b/src/main/kotlin/g3501_3600/s3561_resulting_string_after_adjacent_removals/Solution.kt index ac956215..5dcf8c19 100644 --- a/src/main/kotlin/g3501_3600/s3561_resulting_string_after_adjacent_removals/Solution.kt +++ b/src/main/kotlin/g3501_3600/s3561_resulting_string_after_adjacent_removals/Solution.kt @@ -1,6 +1,6 @@ package g3501_3600.s3561_resulting_string_after_adjacent_removals -// #Medium #2025_05_25_Time_43_ms_(100.00%)_Space_50.83_MB_(68.75%) +// #Medium #String #Stack #Simulation #2025_05_25_Time_43_ms_(100.00%)_Space_50.83_MB_(68.75%) class Solution { fun resultingString(s: String): String { diff --git a/src/main/kotlin/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/Solution.kt b/src/main/kotlin/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/Solution.kt index d0e158af..f02703e9 100644 --- a/src/main/kotlin/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/Solution.kt +++ b/src/main/kotlin/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/Solution.kt @@ -1,6 +1,7 @@ package g3501_3600.s3562_maximum_profit_from_trading_stocks_with_discounts -// #Hard #2025_05_25_Time_40_ms_(100.00%)_Space_49.77_MB_(100.00%) +// #Hard #Array #Dynamic_Programming #Depth_First_Search #Tree +// #2025_05_25_Time_40_ms_(100.00%)_Space_49.77_MB_(100.00%) import kotlin.math.max diff --git a/src/main/kotlin/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/Solution.kt b/src/main/kotlin/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/Solution.kt index 466fece8..79c8063d 100644 --- a/src/main/kotlin/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/Solution.kt +++ b/src/main/kotlin/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/Solution.kt @@ -1,6 +1,6 @@ package g3501_3600.s3563_lexicographically_smallest_string_after_adjacent_removals -// #Hard #2025_05_25_Time_186_ms_(100.00%)_Space_49.04_MB_(100.00%) +// #Hard #String #Dynamic_Programming #2025_05_25_Time_186_ms_(100.00%)_Space_49.04_MB_(100.00%) import kotlin.math.abs