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..dbcf8170 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3556_sum_of_largest_prime_substrings/Solution.kt @@ -0,0 +1,67 @@ +package g3501_3600.s3556_sum_of_largest_prime_substrings + +// #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 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 + } + } + } + } + var sum: Long = 0 + if (first != -1L) { + sum += first + } + if (second != -1L) { + sum += second + } + if (third != -1L) { + sum += third + } + return sum + } + + 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 = 5 + while (i * i <= num) { + if (num % i == 0L || num % (i + 2) == 0L) { + return false + } + i += 6 + } + 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..30efc728 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/Solution.kt @@ -0,0 +1,22 @@ +package g3501_3600.s3557_find_maximum_number_of_non_intersecting_substrings + +// #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 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 r + } +} 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..b07a3257 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.kt @@ -0,0 +1,52 @@ +package g3501_3600.s3558_number_of_ways_to_assign_edge_weights_i + +// #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 { + if (pow2[0] == 0L) { + pow2[0] = 1 + for (i in 1.. 0) { + val v = que[read++] + val u = adj[v] + adj[u] -= v + if (--degrees[u] == 1 && u != 1) { + que[write++] = u + } + } + } + return pow2[distance - 1].toInt() + } + + companion object { + private const val mod = 1e9.toInt() + 7 + private val pow2 = LongArray(100001) + } +} 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..6b2c0914 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/Solution.kt @@ -0,0 +1,99 @@ +package g3501_3600.s3559_number_of_ways_to_assign_edge_weights_ii + +// #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 + +class Solution { + 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[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[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) } + 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..1e2c879c --- /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 #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 { + 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..5dcf8c19 --- /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 #String #Stack #Simulation #2025_05_25_Time_43_ms_(100.00%)_Space_50.83_MB_(68.75%) + +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..f02703e9 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/Solution.kt @@ -0,0 +1,97 @@ +package g3501_3600.s3562_maximum_profit_from_trading_stocks_with_discounts + +// #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 + +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..79c8063d --- /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 + +// #Hard #String #Dynamic_Programming #2025_05_25_Time_186_ms_(100.00%)_Space_49.04_MB_(100.00%) + +import kotlin.math.abs + +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"), + ) + } +}