diff --git a/src/main/kotlin/g3501_3600/s3527_find_the_most_common_response/Solution.kt b/src/main/kotlin/g3501_3600/s3527_find_the_most_common_response/Solution.kt new file mode 100644 index 000000000..5f7f6ed05 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3527_find_the_most_common_response/Solution.kt @@ -0,0 +1,49 @@ +package g3501_3600.s3527_find_the_most_common_response + +// #Medium #Array #String #Hash_Table #Counting +// #2025_04_27_Time_73_ms_(100.00%)_Space_243.97_MB_(50.00%) + +class Solution { + private fun compareStrings(str1: String, str2: String): Boolean { + val n = str1.length + val m = str2.length + var i = 0 + var j = 0 + while (i < n && j < m) { + if (str1[i] < str2[j]) { + return true + } else if (str1[i] > str2[j]) { + return false + } + i++ + j++ + } + return n < m + } + + fun findCommonResponse(responses: List>): String { + val n = responses.size + val mp: MutableMap = HashMap() + var ans = responses[0][0] + var maxFreq = 0 + for (row in 0.. maxFreq || + (ans != resp) && arr[0] == maxFreq && compareStrings(resp, ans) + ) { + ans = resp + maxFreq = arr[0] + } + } + } + return ans + } +} diff --git a/src/main/kotlin/g3501_3600/s3527_find_the_most_common_response/readme.md b/src/main/kotlin/g3501_3600/s3527_find_the_most_common_response/readme.md new file mode 100644 index 000000000..cf8a4616f --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3527_find_the_most_common_response/readme.md @@ -0,0 +1,38 @@ +3527\. Find the Most Common Response + +Medium + +You are given a 2D string array `responses` where each `responses[i]` is an array of strings representing survey responses from the ith day. + +Return the **most common** response across all days after removing **duplicate** responses within each `responses[i]`. If there is a tie, return the _lexicographically smallest_ response. + +**Example 1:** + +**Input:** responses = [["good","ok","good","ok"],["ok","bad","good","ok","ok"],["good"],["bad"]] + +**Output:** "good" + +**Explanation:** + +* After removing duplicates within each list, `responses = [["good", "ok"], ["ok", "bad", "good"], ["good"], ["bad"]]`. +* `"good"` appears 3 times, `"ok"` appears 2 times, and `"bad"` appears 2 times. +* Return `"good"` because it has the highest frequency. + +**Example 2:** + +**Input:** responses = [["good","ok","good"],["ok","bad"],["bad","notsure"],["great","good"]] + +**Output:** "bad" + +**Explanation:** + +* After removing duplicates within each list we have `responses = [["good", "ok"], ["ok", "bad"], ["bad", "notsure"], ["great", "good"]]`. +* `"bad"`, `"good"`, and `"ok"` each occur 2 times. +* The output is `"bad"` because it is the lexicographically smallest amongst the words with the highest frequency. + +**Constraints:** + +* `1 <= responses.length <= 1000` +* `1 <= responses[i].length <= 1000` +* `1 <= responses[i][j].length <= 10` +* `responses[i][j]` consists of only lowercase English letters \ No newline at end of file diff --git a/src/main/kotlin/g3501_3600/s3528_unit_conversion_i/Solution.kt b/src/main/kotlin/g3501_3600/s3528_unit_conversion_i/Solution.kt new file mode 100644 index 000000000..b5aca3b0f --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3528_unit_conversion_i/Solution.kt @@ -0,0 +1,16 @@ +package g3501_3600.s3528_unit_conversion_i + +// #Medium #Depth_First_Search #Breadth_First_Search #Graph +// #2025_04_27_Time_3_ms_(100.00%)_Space_128.33_MB_(100.00%) + +class Solution { + fun baseUnitConversions(conversions: Array): IntArray { + val arr = IntArray(conversions.size + 1) + arr[0] = 1 + for (conversion in conversions) { + val `val` = (arr[conversion[0]].toLong() * conversion[2]) % 1000000007 + arr[conversion[1]] = `val`.toInt() + } + return arr + } +} diff --git a/src/main/kotlin/g3501_3600/s3528_unit_conversion_i/readme.md b/src/main/kotlin/g3501_3600/s3528_unit_conversion_i/readme.md new file mode 100644 index 000000000..4b0fdcf00 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3528_unit_conversion_i/readme.md @@ -0,0 +1,44 @@ +3528\. Unit Conversion I + +Medium + +There are `n` types of units indexed from `0` to `n - 1`. You are given a 2D integer array `conversions` of length `n - 1`, where conversions[i] = [sourceUniti, targetUniti, conversionFactori]. This indicates that a single unit of type sourceUniti is equivalent to conversionFactori units of type targetUniti. + +Return an array `baseUnitConversion` of length `n`, where `baseUnitConversion[i]` is the number of units of type `i` equivalent to a single unit of type 0. Since the answer may be large, return each `baseUnitConversion[i]` **modulo** 109 + 7. + +**Example 1:** + +**Input:** conversions = [[0,1,2],[1,2,3]] + +**Output:** [1,2,6] + +**Explanation:** + +* Convert a single unit of type 0 into 2 units of type 1 using `conversions[0]`. +* Convert a single unit of type 0 into 6 units of type 2 using `conversions[0]`, then `conversions[1]`. + +![](https://assets.leetcode.com/uploads/2025/03/12/example1.png) + +**Example 2:** + +**Input:** conversions = [[0,1,2],[0,2,3],[1,3,4],[1,4,5],[2,5,2],[4,6,3],[5,7,4]] + +**Output:** [1,2,3,8,10,6,30,24] + +**Explanation:** + +* Convert a single unit of type 0 into 2 units of type 1 using `conversions[0]`. +* Convert a single unit of type 0 into 3 units of type 2 using `conversions[1]`. +* Convert a single unit of type 0 into 8 units of type 3 using `conversions[0]`, then `conversions[2]`. +* Convert a single unit of type 0 into 10 units of type 4 using `conversions[0]`, then `conversions[3]`. +* Convert a single unit of type 0 into 6 units of type 5 using `conversions[1]`, then `conversions[4]`. +* Convert a single unit of type 0 into 30 units of type 6 using `conversions[0]`, `conversions[3]`, then `conversions[5]`. +* Convert a single unit of type 0 into 24 units of type 7 using `conversions[1]`, `conversions[4]`, then `conversions[6]`. + +**Constraints:** + +* 2 <= n <= 105 +* `conversions.length == n - 1` +* 0 <= sourceUniti, targetUniti < n +* 1 <= conversionFactori <= 109 +* It is guaranteed that unit 0 can be converted into any other unit through a **unique** combination of conversions without using any conversions in the opposite direction. \ No newline at end of file diff --git a/src/main/kotlin/g3501_3600/s3529_count_cells_in_overlapping_horizontal_and_vertical_substrings/Solution.kt b/src/main/kotlin/g3501_3600/s3529_count_cells_in_overlapping_horizontal_and_vertical_substrings/Solution.kt new file mode 100644 index 000000000..8b6204303 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3529_count_cells_in_overlapping_horizontal_and_vertical_substrings/Solution.kt @@ -0,0 +1,91 @@ +package g3501_3600.s3529_count_cells_in_overlapping_horizontal_and_vertical_substrings + +// #Medium #Array #String #Matrix #Hash_Function #String_Matching #Rolling_Hash +// #2025_04_27_Time_51_ms_(100.00%)_Space_85.31_MB_(100.00%) + +class Solution { + fun countCells(grid: Array, pattern: String): Int { + val k = pattern.length + val lps = makeLps(pattern) + val m = grid.size + val n = grid[0].size + val horiPats = Array(m) { IntArray(n) } + val vertPats = Array(m) { IntArray(n) } + var i = 0 + var j = 0 + while (i < m * n) { + if (grid[i / n][i % n] == pattern[j]) { + i++ + if (++j == k) { + val d = i - j + horiPats[d / n][d % n] = horiPats[d / n][d % n] + 1 + if (i < m * n) { + horiPats[i / n][i % n] = horiPats[i / n][i % n] - 1 + } + j = lps[j - 1] + } + } else if (j != 0) { + j = lps[j - 1] + } else { + i++ + } + } + i = 0 + j = 0 + // now do vert pattern, use i = 0 to m*n -1 but instead index as grid[i % m][i/m] + while (i < m * n) { + if (grid[i % m][i / m] == pattern[j]) { + i++ + if (++j == k) { + val d = i - j + vertPats[d % m][d / m] = vertPats[d % m][d / m] + 1 + if (i < m * n) { + vertPats[i % m][i / m] = vertPats[i % m][i / m] - 1 + } + j = lps[j - 1] + } + } else if (j != 0) { + j = lps[j - 1] + } else { + i++ + } + } + i = 1 + while (i < m * n) { + vertPats[i % m][i / m] += vertPats[(i - 1) % m][(i - 1) / m] + horiPats[i / n][i % n] += horiPats[(i - 1) / n][(i - 1) % n] + i++ + } + var res = 0 + i = 0 + while (i < m) { + j = 0 + while (j < n) { + if (horiPats[i][j] > 0 && vertPats[i][j] > 0) { + res++ + } + j++ + } + i++ + } + return res + } + + private fun makeLps(pattern: String): IntArray { + val n = pattern.length + val lps = IntArray(n) + var len = 0 + var i = 1 + lps[0] = 0 + while (i < n) { + if (pattern[i] == pattern[len]) { + lps[i++] = ++len + } else if (len != 0) { + len = lps[len - 1] + } else { + lps[i++] = 0 + } + } + return lps + } +} diff --git a/src/main/kotlin/g3501_3600/s3529_count_cells_in_overlapping_horizontal_and_vertical_substrings/readme.md b/src/main/kotlin/g3501_3600/s3529_count_cells_in_overlapping_horizontal_and_vertical_substrings/readme.md new file mode 100644 index 000000000..7c70f45b6 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3529_count_cells_in_overlapping_horizontal_and_vertical_substrings/readme.md @@ -0,0 +1,54 @@ +3529\. Count Cells in Overlapping Horizontal and Vertical Substrings + +Medium + +You are given an `m x n` matrix `grid` consisting of characters and a string `pattern`. + +A **horizontal substring** is a contiguous sequence of characters read from left to right. If the end of a row is reached before the substring is complete, it wraps to the first column of the next row and continues as needed. You do **not** wrap from the bottom row back to the top. + +A **vertical substring** is a contiguous sequence of characters read from top to bottom. If the bottom of a column is reached before the substring is complete, it wraps to the first row of the next column and continues as needed. You do **not** wrap from the last column back to the first. + +Count the number of cells in the matrix that satisfy the following condition: + +* The cell must be part of **at least** one horizontal substring and **at least** one vertical substring, where **both** substrings are equal to the given `pattern`. + +Return the count of these cells. + +**Example 1:** + +![](https://assets.leetcode.com/uploads/2025/03/03/gridtwosubstringsdrawio.png) + +**Input:** grid = [["a","a","c","c"],["b","b","b","c"],["a","a","b","a"],["c","a","a","c"],["a","a","c","c"]], pattern = "abaca" + +**Output:** 1 + +**Explanation:** + +The pattern `"abaca"` appears once as a horizontal substring (colored blue) and once as a vertical substring (colored red), intersecting at one cell (colored purple). + +**Example 2:** + +![](https://assets.leetcode.com/uploads/2025/03/03/gridexample2fixeddrawio.png) + +**Input:** grid = [["c","a","a","a"],["a","a","b","a"],["b","b","a","a"],["a","a","b","a"]], pattern = "aba" + +**Output:** 4 + +**Explanation:** + +The cells colored above are all part of at least one horizontal and one vertical substring matching the pattern `"aba"`. + +**Example 3:** + +**Input:** grid = [["a"]], pattern = "a" + +**Output:** 1 + +**Constraints:** + +* `m == grid.length` +* `n == grid[i].length` +* `1 <= m, n <= 1000` +* 1 <= m * n <= 105 +* `1 <= pattern.length <= m * n` +* `grid` and `pattern` consist of only lowercase English letters. \ No newline at end of file diff --git a/src/main/kotlin/g3501_3600/s3530_maximum_profit_from_valid_topological_order_in_dag/Solution.kt b/src/main/kotlin/g3501_3600/s3530_maximum_profit_from_valid_topological_order_in_dag/Solution.kt new file mode 100644 index 000000000..093a5287e --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3530_maximum_profit_from_valid_topological_order_in_dag/Solution.kt @@ -0,0 +1,59 @@ +package g3501_3600.s3530_maximum_profit_from_valid_topological_order_in_dag + +// #Hard #Array #Dynamic_Programming #Bit_Manipulation #Graph #Bitmask #Topological_Sort +// #2025_04_27_Time_833_ms_(100.00%)_Space_78.65_MB_(100.00%) + +import kotlin.math.max + +class Solution { + private fun helper( + mask: Int, + pos: Int, + inDegree: IntArray, + adj: List>, + score: IntArray, + dp: IntArray, + n: Int, + ): Int { + if (mask == (1 shl n) - 1) { + return 0 + } + if (dp[mask] != -1) { + return dp[mask] + } + var res = 0 + for (i in 0.., score: IntArray): Int { + val adj: MutableList> = ArrayList>() + for (i in 0..()) + } + val inDegree = IntArray(n) + for (e in edges) { + adj[e[0]].add(e[1]) + inDegree[e[1]]++ + } + val dp = IntArray(1 shl n) + dp.fill(-1) + return helper(0, 1, inDegree, adj, score, dp, n) + } +} diff --git a/src/main/kotlin/g3501_3600/s3530_maximum_profit_from_valid_topological_order_in_dag/readme.md b/src/main/kotlin/g3501_3600/s3530_maximum_profit_from_valid_topological_order_in_dag/readme.md new file mode 100644 index 000000000..867666b5b --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3530_maximum_profit_from_valid_topological_order_in_dag/readme.md @@ -0,0 +1,63 @@ +3530\. Maximum Profit from Valid Topological Order in DAG + +Hard + +You are given a **Directed Acyclic Graph (DAG)** with `n` nodes labeled from `0` to `n - 1`, represented by a 2D array `edges`, where edges[i] = [ui, vi] indicates a directed edge from node ui to vi. Each node has an associated **score** given in an array `score`, where `score[i]` represents the score of node `i`. + +You must process the nodes in a **valid topological order**. Each node is assigned a **1-based position** in the processing order. + +The **profit** is calculated by summing up the product of each node's score and its position in the ordering. + +Return the **maximum** possible profit achievable with an optimal topological order. + +A **topological order** of a DAG is a linear ordering of its nodes such that for every directed edge `u → v`, node `u` comes before `v` in the ordering. + +**Example 1:** + +**Input:** n = 2, edges = [[0,1]], score = [2,3] + +**Output:** 8 + +**Explanation:** + +![](https://assets.leetcode.com/uploads/2025/03/10/screenshot-2025-03-11-at-021131.png) + +Node 1 depends on node 0, so a valid order is `[0, 1]`. + +| Node | Processing Order | Score | Multiplier | Profit Calculation | +|------|------------------|-------|------------|--------------------| +| 0 | 1st | 2 | 1 | 2 × 1 = 2 | +| 1 | 2nd | 3 | 2 | 3 × 2 = 6 | + +The maximum total profit achievable over all valid topological orders is `2 + 6 = 8`. + +**Example 2:** + +**Input:** n = 3, edges = [[0,1],[0,2]], score = [1,6,3] + +**Output:** 25 + +**Explanation:** + +![](https://assets.leetcode.com/uploads/2025/03/10/screenshot-2025-03-11-at-023558.png) + +Nodes 1 and 2 depend on node 0, so the most optimal valid order is `[0, 2, 1]`. + +| Node | Processing Order | Score | Multiplier | Profit Calculation | +|------|------------------|-------|------------|--------------------| +| 0 | 1st | 1 | 1 | 1 × 1 = 1 | +| 2 | 2nd | 3 | 2 | 3 × 2 = 6 | +| 1 | 3rd | 6 | 3 | 6 × 3 = 18 | + +The maximum total profit achievable over all valid topological orders is `1 + 6 + 18 = 25`. + +**Constraints:** + +* `1 <= n == score.length <= 22` +* 1 <= score[i] <= 105 +* `0 <= edges.length <= n * (n - 1) / 2` +* edges[i] == [ui, vi] denotes a directed edge from ui to vi. +* 0 <= ui, vi < n +* ui != vi +* The input graph is **guaranteed** to be a **DAG**. +* There are no duplicate edges. \ No newline at end of file diff --git a/src/main/kotlin/g3501_3600/s3531_count_covered_buildings/Solution.kt b/src/main/kotlin/g3501_3600/s3531_count_covered_buildings/Solution.kt new file mode 100644 index 000000000..1acbcb657 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3531_count_covered_buildings/Solution.kt @@ -0,0 +1,38 @@ +package g3501_3600.s3531_count_covered_buildings + +// #Medium #Array #Hash_Table #Sorting #2025_04_27_Time_34_ms_(100.00%)_Space_119.08_MB_(80.00%) + +import kotlin.math.max +import kotlin.math.min + +class Solution { + private fun helper(buildings: Array, n: Int): Int { + val minRow = IntArray(n + 1) + val maxRow = IntArray(n + 1) + val minCol = IntArray(n + 1) + val maxCol = IntArray(n + 1) + minRow.fill(n + 1) + minCol.fill(n + 1) + for (b in buildings) { + val x = b[0] + val y = b[1] + minRow[x] = min(minRow[x], y) + maxRow[x] = max(maxRow[x], y) + minCol[y] = min(minCol[y], x) + maxCol[y] = max(maxCol[y], x) + } + var ans = 0 + for (arr in buildings) { + val x = arr[0] + val y = arr[1] + if (minRow[x] < y && maxRow[x] > y && minCol[y] < x && maxCol[y] > x) { + ans++ + } + } + return ans + } + + fun countCoveredBuildings(n: Int, buildings: Array): Int { + return helper(buildings, n) + } +} diff --git a/src/main/kotlin/g3501_3600/s3531_count_covered_buildings/readme.md b/src/main/kotlin/g3501_3600/s3531_count_covered_buildings/readme.md new file mode 100644 index 000000000..f491af619 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3531_count_covered_buildings/readme.md @@ -0,0 +1,63 @@ +3531\. Count Covered Buildings + +Medium + +You are given a positive integer `n`, representing an `n x n` city. You are also given a 2D grid `buildings`, where `buildings[i] = [x, y]` denotes a **unique** building located at coordinates `[x, y]`. + +A building is **covered** if there is at least one building in all **four** directions: left, right, above, and below. + +Return the number of **covered** buildings. + +**Example 1:** + +![](https://assets.leetcode.com/uploads/2025/03/04/telegram-cloud-photo-size-5-6212982906394101085-m.jpg) + +**Input:** n = 3, buildings = [[1,2],[2,2],[3,2],[2,1],[2,3]] + +**Output:** 1 + +**Explanation:** + +* Only building `[2,2]` is covered as it has at least one building: + * above (`[1,2]`) + * below (`[3,2]`) + * left (`[2,1]`) + * right (`[2,3]`) +* Thus, the count of covered buildings is 1. + +**Example 2:** + +![](https://assets.leetcode.com/uploads/2025/03/04/telegram-cloud-photo-size-5-6212982906394101086-m.jpg) + +**Input:** n = 3, buildings = [[1,1],[1,2],[2,1],[2,2]] + +**Output:** 0 + +**Explanation:** + +* No building has at least one building in all four directions. + +**Example 3:** + +![](https://assets.leetcode.com/uploads/2025/03/16/telegram-cloud-photo-size-5-6248862251436067566-x.jpg) + +**Input:** n = 5, buildings = [[1,3],[3,2],[3,3],[3,5],[5,3]] + +**Output:** 1 + +**Explanation:** + +* Only building `[3,3]` is covered as it has at least one building: + * above (`[1,3]`) + * below (`[5,3]`) + * left (`[3,2]`) + * right (`[3,5]`) +* Thus, the count of covered buildings is 1. + +**Constraints:** + +* 2 <= n <= 105 +* 1 <= buildings.length <= 105 +* `buildings[i] = [x, y]` +* `1 <= x, y <= n` +* All coordinates of `buildings` are **unique**. \ No newline at end of file diff --git a/src/main/kotlin/g3501_3600/s3532_path_existence_queries_in_a_graph_i/Solution.kt b/src/main/kotlin/g3501_3600/s3532_path_existence_queries_in_a_graph_i/Solution.kt new file mode 100644 index 000000000..5659349a3 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3532_path_existence_queries_in_a_graph_i/Solution.kt @@ -0,0 +1,27 @@ +package g3501_3600.s3532_path_existence_queries_in_a_graph_i + +// #Medium #Array #Binary_Search #Graph #Union_Find +// #2025_04_27_Time_5_ms_(90.91%)_Space_126.78_MB_(9.09%) + +class Solution { + fun pathExistenceQueries(n: Int, nums: IntArray, maxDiff: Int, queries: Array): BooleanArray { + val comp = IntArray(n) + var compId = 0 + comp[0] = 0 + for (i in 1..queries[i] = [ui, vi], determine whether there exists a path between nodes ui and vi. + +Return a boolean array `answer`, where `answer[i]` is `true` if there exists a path between ui and vi in the ith query and `false` otherwise. + +**Example 1:** + +**Input:** n = 2, nums = [1,3], maxDiff = 1, queries = [[0,0],[0,1]] + +**Output:** [true,false] + +**Explanation:** + +* Query `[0,0]`: Node 0 has a trivial path to itself. +* Query `[0,1]`: There is no edge between Node 0 and Node 1 because `|nums[0] - nums[1]| = |1 - 3| = 2`, which is greater than `maxDiff`. +* Thus, the final answer after processing all the queries is `[true, false]`. + +**Example 2:** + +**Input:** n = 4, nums = [2,5,6,8], maxDiff = 2, queries = [[0,1],[0,2],[1,3],[2,3]] + +**Output:** [false,false,true,true] + +**Explanation:** + +The resulting graph is: + +![](https://assets.leetcode.com/uploads/2025/03/25/screenshot-2025-03-26-at-122249.png) + +* Query `[0,1]`: There is no edge between Node 0 and Node 1 because `|nums[0] - nums[1]| = |2 - 5| = 3`, which is greater than `maxDiff`. +* Query `[0,2]`: There is no edge between Node 0 and Node 2 because `|nums[0] - nums[2]| = |2 - 6| = 4`, which is greater than `maxDiff`. +* Query `[1,3]`: There is a path between Node 1 and Node 3 through Node 2 since `|nums[1] - nums[2]| = |5 - 6| = 1` and `|nums[2] - nums[3]| = |6 - 8| = 2`, both of which are within `maxDiff`. +* Query `[2,3]`: There is an edge between Node 2 and Node 3 because `|nums[2] - nums[3]| = |6 - 8| = 2`, which is equal to `maxDiff`. +* Thus, the final answer after processing all the queries is `[false, false, true, true]`. + +**Constraints:** + +* 1 <= n == nums.length <= 105 +* 0 <= nums[i] <= 105 +* `nums` is sorted in **non-decreasing** order. +* 0 <= maxDiff <= 105 +* 1 <= queries.length <= 105 +* queries[i] == [ui, vi] +* 0 <= ui, vi < n \ No newline at end of file diff --git a/src/main/kotlin/g3501_3600/s3533_concatenated_divisibility/Solution.kt b/src/main/kotlin/g3501_3600/s3533_concatenated_divisibility/Solution.kt new file mode 100644 index 000000000..5fe475c3e --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3533_concatenated_divisibility/Solution.kt @@ -0,0 +1,73 @@ +package g3501_3600.s3533_concatenated_divisibility + +// #Hard #Array #Dynamic_Programming #Bit_Manipulation #Bitmask +// #2025_04_27_Time_20_ms_(100.00%)_Space_49.10_MB_(100.00%) + +@Suppress("kotlin:S107") +class Solution { + fun concatenatedDivisibility(nums: IntArray, k: Int): IntArray { + nums.sort() + var digits = 0 + val n = nums.size + val digCnt = IntArray(n) + for (i in 0..= 10) { + digits++ + digCnt[i]++ + num /= 10 + } + } + val pow10 = IntArray(digits + 1) + pow10[0] = 1 + for (i in 1..digits) { + pow10[i] = (pow10[i - 1] * 10) % k + } + val res = IntArray(n) + return if (dfs(0, 0, k, digCnt, nums, pow10, Array(1 shl n) { BooleanArray(k) }, 0, res, n)) { + res + } else { + IntArray(0) + } + } + + private fun dfs( + mask: Int, + residue: Int, + k: Int, + digCnt: IntArray, + nums: IntArray, + pow10: IntArray, + visited: Array, + ansIdx: Int, + ans: IntArray, + n: Int, + ): Boolean { + if (ansIdx == n) { + return residue == 0 + } + if (visited[mask][residue]) { + return false + } + var i = 0 + var bit = 1 + while (i < n) { + if ((mask and bit) == bit) { + i++ + bit = bit shl 1 + continue + } + val newResidue = (residue * pow10[digCnt[i]] + nums[i]) % k + ans[ansIdx] = nums[i] + if (dfs(mask or bit, newResidue, k, digCnt, nums, pow10, visited, ansIdx + 1, ans, n)) { + return true + } + i++ + bit = bit shl 1 + } + visited[mask][residue] = true + return false + } +} diff --git a/src/main/kotlin/g3501_3600/s3533_concatenated_divisibility/readme.md b/src/main/kotlin/g3501_3600/s3533_concatenated_divisibility/readme.md new file mode 100644 index 000000000..789cc1d9f --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3533_concatenated_divisibility/readme.md @@ -0,0 +1,59 @@ +3533\. Concatenated Divisibility + +Hard + +You are given an array of positive integers `nums` and a positive integer `k`. + +A permutation of `nums` is said to form a **divisible concatenation** if, when you _concatenate_ _the decimal representations_ of the numbers in the order specified by the permutation, the resulting number is **divisible by** `k`. + +Return the **lexicographically smallest** permutation (when considered as a list of integers) that forms a **divisible concatenation**. If no such permutation exists, return an empty list. + +**Example 1:** + +**Input:** nums = [3,12,45], k = 5 + +**Output:** [3,12,45] + +**Explanation:** + +| Permutation | Concatenated Value | Divisible by 5 | +|-------------|--------------------|----------------| +| [3, 12, 45] | 31245 | Yes | +| [3, 45, 12] | 34512 | No | +| [12, 3, 45] | 12345 | Yes | +| [12, 45, 3] | 12453 | No | +| [45, 3, 12] | 45312 | No | +| [45, 12, 3] | 45123 | No | + +The lexicographically smallest permutation that forms a divisible concatenation is `[3,12,45]`. + +**Example 2:** + +**Input:** nums = [10,5], k = 10 + +**Output:** [5,10] + +**Explanation:** + +| Permutation | Concatenated Value | Divisible by 10 | +|-------------|--------------------|-----------------| +| [5, 10] | 510 | Yes | +| [10, 5] | 105 | No | + +The lexicographically smallest permutation that forms a divisible concatenation is `[5,10]`. + +**Example 3:** + +**Input:** nums = [1,2,3], k = 5 + +**Output:** [] + +**Explanation:** + +Since no permutation of `nums` forms a valid divisible concatenation, return an empty list. + +**Constraints:** + +* `1 <= nums.length <= 13` +* 1 <= nums[i] <= 105 +* `1 <= k <= 100` \ No newline at end of file diff --git a/src/main/kotlin/g3501_3600/s3534_path_existence_queries_in_a_graph_ii/Solution.kt b/src/main/kotlin/g3501_3600/s3534_path_existence_queries_in_a_graph_ii/Solution.kt new file mode 100644 index 000000000..e68c934b6 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3534_path_existence_queries_in_a_graph_ii/Solution.kt @@ -0,0 +1,82 @@ +package g3501_3600.s3534_path_existence_queries_in_a_graph_ii + +// #Hard #Array #Sorting #Greedy #Binary_Search #Graph +// #2025_04_27_Time_152_ms_(100.00%)_Space_132.11_MB_(100.00%) + +import kotlin.math.abs + +class Solution { + fun pathExistenceQueries(n: Int, nums: IntArray, maxDiff: Int, queries: Array): IntArray { + val position = IntArray(n) + val values = IntArray(n) + val sortedIndices = Array(n) { i -> i } + sortedIndices.sortWith { a: Int, b: Int -> nums[a].compareTo(nums[b]) } + for (i in 0.. endPos) { + val temp = startPos + startPos = endPos + endPos = temp + } + if (abs(nums[start] - nums[end]) <= maxDiff) { + results[idx] = 1 + continue + } + if (reachableIndex[startPos] < endPos) { + var current = startPos + var jumpCount = 0 + for (k in maxLog - 1 downTo 0) { + if (upTable[k][current] < endPos) { + if (upTable[k][current] == current) { + break + } + current = upTable[k][current] + jumpCount += 1 shl k + } + } + if (reachableIndex[current] >= endPos) { + results[idx] = jumpCount + 1 + } else { + results[idx] = -1 + } + } else { + results[idx] = 1 + } + } + return results + } +} diff --git a/src/main/kotlin/g3501_3600/s3534_path_existence_queries_in_a_graph_ii/readme.md b/src/main/kotlin/g3501_3600/s3534_path_existence_queries_in_a_graph_ii/readme.md new file mode 100644 index 000000000..4554c5084 --- /dev/null +++ b/src/main/kotlin/g3501_3600/s3534_path_existence_queries_in_a_graph_ii/readme.md @@ -0,0 +1,82 @@ +3534\. Path Existence Queries in a Graph II + +Hard + +You are given an integer `n` representing the number of nodes in a graph, labeled from 0 to `n - 1`. + +You are also given an integer array `nums` of length `n` and an integer `maxDiff`. + +An **undirected** edge exists between nodes `i` and `j` if the **absolute** difference between `nums[i]` and `nums[j]` is **at most** `maxDiff` (i.e., `|nums[i] - nums[j]| <= maxDiff`). + +You are also given a 2D integer array `queries`. For each queries[i] = [ui, vi], find the **minimum** distance between nodes ui and vi. If no path exists between the two nodes, return -1 for that query. + +Return an array `answer`, where `answer[i]` is the result of the ith query. + +**Note:** The edges between the nodes are unweighted. + +**Example 1:** + +**Input:** n = 5, nums = [1,8,3,4,2], maxDiff = 3, queries = [[0,3],[2,4]] + +**Output:** [1,1] + +**Explanation:** + +The resulting graph is: + +![](https://assets.leetcode.com/uploads/2025/03/25/4149example1drawio.png) + +| Query | Shortest Path | Minimum Distance | +|--------|----------------|------------------| +| [0, 3] | 0 → 3 | 1 | +| [2, 4] | 2 → 4 | 1 | + +Thus, the output is `[1, 1]`. + +**Example 2:** + +**Input:** n = 5, nums = [5,3,1,9,10], maxDiff = 2, queries = [[0,1],[0,2],[2,3],[4,3]] + +**Output:** [1,2,-1,1] + +**Explanation:** + +The resulting graph is: + +![](https://assets.leetcode.com/uploads/2025/03/25/4149example2drawio.png) + +Here is the equivalent Markdown for the given HTML table: + +| Query | Shortest Path | Minimum Distance | +|--------|----------------|------------------| +| [0, 1] | 0 → 1 | 1 | +| [0, 2] | 0 → 1 → 2 | 2 | +| [2, 3] | None | -1 | +| [4, 3] | 3 → 4 | 1 | + +Thus, the output is `[1, 2, -1, 1]`. + +**Example 3:** + +**Input:** n = 3, nums = [3,6,1], maxDiff = 1, queries = [[0,0],[0,1],[1,2]] + +**Output:** [0,-1,-1] + +**Explanation:** + +There are no edges between any two nodes because: + +* Nodes 0 and 1: `|nums[0] - nums[1]| = |3 - 6| = 3 > 1` +* Nodes 0 and 2: `|nums[0] - nums[2]| = |3 - 1| = 2 > 1` +* Nodes 1 and 2: `|nums[1] - nums[2]| = |6 - 1| = 5 > 1` + +Thus, no node can reach any other node, and the output is `[0, -1, -1]`. + +**Constraints:** + +* 1 <= n == nums.length <= 105 +* 0 <= nums[i] <= 105 +* 0 <= maxDiff <= 105 +* 1 <= queries.length <= 105 +* queries[i] == [ui, vi] +* 0 <= ui, vi < n \ No newline at end of file diff --git a/src/test/kotlin/g3501_3600/s3527_find_the_most_common_response/SolutionTest.kt b/src/test/kotlin/g3501_3600/s3527_find_the_most_common_response/SolutionTest.kt new file mode 100644 index 000000000..7fd1679f9 --- /dev/null +++ b/src/test/kotlin/g3501_3600/s3527_find_the_most_common_response/SolutionTest.kt @@ -0,0 +1,56 @@ +package g3501_3600.s3527_find_the_most_common_response + +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Test + +internal class SolutionTest { + @Test + fun findCommonResponse() { + assertThat( + Solution() + .findCommonResponse( + listOf( + mutableListOf("good", "ok", "good", "ok"), + mutableListOf("ok", "bad", "good", "ok", "ok"), + mutableListOf("good"), + mutableListOf("bad"), + ), + ), + equalTo("good"), + ) + } + + @Test + fun findCommonResponse2() { + assertThat( + Solution() + .findCommonResponse( + listOf( + listOf("good", "ok", "good"), + listOf("ok", "bad"), + listOf("bad", "notsure"), + listOf("great", "good"), + ), + ), + equalTo("bad"), + ) + } + + @Test + fun findCommonResponse3() { + assertThat( + Solution() + .findCommonResponse( + listOf( + listOf("fed", "vgdb", "w", "zs", "fed"), + listOf("f", "cz", "pah", "gj", "rpxr", "ugyi"), + listOf("t", "oja", "c"), + listOf("ni", "fed", "mcox", "a", "f", "ni", "g"), + listOf("ybk", "xght", "jje"), + ), + ), + equalTo("f"), + ) + } +} diff --git a/src/test/kotlin/g3501_3600/s3528_unit_conversion_i/SolutionTest.kt b/src/test/kotlin/g3501_3600/s3528_unit_conversion_i/SolutionTest.kt new file mode 100644 index 000000000..07e0e3321 --- /dev/null +++ b/src/test/kotlin/g3501_3600/s3528_unit_conversion_i/SolutionTest.kt @@ -0,0 +1,34 @@ +package g3501_3600.s3528_unit_conversion_i + +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Test + +internal class SolutionTest { + @Test + fun baseUnitConversions() { + assertThat( + Solution().baseUnitConversions(arrayOf(intArrayOf(0, 1, 2), intArrayOf(1, 2, 3))), + equalTo(intArrayOf(1, 2, 6)), + ) + } + + @Test + fun baseUnitConversions2() { + assertThat( + Solution() + .baseUnitConversions( + arrayOf( + intArrayOf(0, 1, 2), + intArrayOf(0, 2, 3), + intArrayOf(1, 3, 4), + intArrayOf(1, 4, 5), + intArrayOf(2, 5, 2), + intArrayOf(4, 6, 3), + intArrayOf(5, 7, 4), + ), + ), + equalTo(intArrayOf(1, 2, 3, 8, 10, 6, 30, 24)), + ) + } +} diff --git a/src/test/kotlin/g3501_3600/s3529_count_cells_in_overlapping_horizontal_and_vertical_substrings/SolutionTest.kt b/src/test/kotlin/g3501_3600/s3529_count_cells_in_overlapping_horizontal_and_vertical_substrings/SolutionTest.kt new file mode 100644 index 000000000..003a08193 --- /dev/null +++ b/src/test/kotlin/g3501_3600/s3529_count_cells_in_overlapping_horizontal_and_vertical_substrings/SolutionTest.kt @@ -0,0 +1,50 @@ +package g3501_3600.s3529_count_cells_in_overlapping_horizontal_and_vertical_substrings + +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Test + +internal class SolutionTest { + @Test + fun countCells() { + assertThat( + Solution() + .countCells( + arrayOf( + charArrayOf('a', 'a', 'c', 'c'), + charArrayOf('b', 'b', 'b', 'c'), + charArrayOf('a', 'a', 'b', 'a'), + charArrayOf('c', 'a', 'a', 'c'), + charArrayOf('a', 'a', 'c', 'c'), + ), + "abaca", + ), + equalTo(1), + ) + } + + @Test + fun countCells2() { + assertThat( + Solution() + .countCells( + arrayOf( + charArrayOf('c', 'a', 'a', 'a'), + charArrayOf('a', 'a', 'b', 'a'), + charArrayOf('b', 'b', 'a', 'a'), + charArrayOf('a', 'a', 'b', 'a'), + ), + "aba", + ), + equalTo(4), + ) + } + + @Test + fun countCells3() { + assertThat( + Solution().countCells(arrayOf(charArrayOf('a')), "a"), + equalTo(1), + ) + } +} diff --git a/src/test/kotlin/g3501_3600/s3530_maximum_profit_from_valid_topological_order_in_dag/SolutionTest.kt b/src/test/kotlin/g3501_3600/s3530_maximum_profit_from_valid_topological_order_in_dag/SolutionTest.kt new file mode 100644 index 000000000..8f8ec97cf --- /dev/null +++ b/src/test/kotlin/g3501_3600/s3530_maximum_profit_from_valid_topological_order_in_dag/SolutionTest.kt @@ -0,0 +1,23 @@ +package g3501_3600.s3530_maximum_profit_from_valid_topological_order_in_dag + +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, arrayOf(intArrayOf(0, 1)), intArrayOf(2, 3)), + equalTo(8), + ) + } + + @Test + fun maxProfit2() { + assertThat( + Solution().maxProfit(3, arrayOf(intArrayOf(0, 1), intArrayOf(0, 2)), intArrayOf(1, 6, 3)), + equalTo(25), + ) + } +} diff --git a/src/test/kotlin/g3501_3600/s3531_count_covered_buildings/SolutionTest.kt b/src/test/kotlin/g3501_3600/s3531_count_covered_buildings/SolutionTest.kt new file mode 100644 index 000000000..49aeb2849 --- /dev/null +++ b/src/test/kotlin/g3501_3600/s3531_count_covered_buildings/SolutionTest.kt @@ -0,0 +1,55 @@ +package g3501_3600.s3531_count_covered_buildings + +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Test + +internal class SolutionTest { + @Test + fun countCoveredBuildings() { + assertThat( + Solution() + .countCoveredBuildings( + 3, + arrayOf( + intArrayOf(1, 2), + intArrayOf(2, 2), + intArrayOf(3, 2), + intArrayOf(2, 1), + intArrayOf(2, 3), + ), + ), + equalTo(1), + ) + } + + @Test + fun countCoveredBuildings2() { + assertThat( + Solution() + .countCoveredBuildings( + 3, + arrayOf(intArrayOf(1, 1), intArrayOf(1, 2), intArrayOf(2, 1), intArrayOf(2, 2)), + ), + equalTo(0), + ) + } + + @Test + fun countCoveredBuildings3() { + assertThat( + Solution() + .countCoveredBuildings( + 5, + arrayOf( + intArrayOf(1, 3), + intArrayOf(3, 2), + intArrayOf(3, 3), + intArrayOf(3, 5), + intArrayOf(5, 3), + ), + ), + equalTo(1), + ) + } +} diff --git a/src/test/kotlin/g3501_3600/s3532_path_existence_queries_in_a_graph_i/SolutionTest.kt b/src/test/kotlin/g3501_3600/s3532_path_existence_queries_in_a_graph_i/SolutionTest.kt new file mode 100644 index 000000000..cf2c405d3 --- /dev/null +++ b/src/test/kotlin/g3501_3600/s3532_path_existence_queries_in_a_graph_i/SolutionTest.kt @@ -0,0 +1,30 @@ +package g3501_3600.s3532_path_existence_queries_in_a_graph_i + +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Test + +internal class SolutionTest { + @Test + fun pathExistenceQueries() { + assertThat( + Solution() + .pathExistenceQueries(2, intArrayOf(1, 3), 1, arrayOf(intArrayOf(0, 0), intArrayOf(0, 1))), + equalTo(booleanArrayOf(true, false)), + ) + } + + @Test + fun pathExistenceQueries2() { + assertThat( + Solution() + .pathExistenceQueries( + 4, + intArrayOf(2, 5, 6, 8), + 2, + arrayOf(intArrayOf(0, 1), intArrayOf(0, 2), intArrayOf(1, 3), intArrayOf(2, 3)), + ), + equalTo(booleanArrayOf(false, false, true, true)), + ) + } +} diff --git a/src/test/kotlin/g3501_3600/s3533_concatenated_divisibility/SolutionTest.kt b/src/test/kotlin/g3501_3600/s3533_concatenated_divisibility/SolutionTest.kt new file mode 100644 index 000000000..6acf76ef5 --- /dev/null +++ b/src/test/kotlin/g3501_3600/s3533_concatenated_divisibility/SolutionTest.kt @@ -0,0 +1,31 @@ +package g3501_3600.s3533_concatenated_divisibility + +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Test + +internal class SolutionTest { + @Test + fun concatenatedDivisibility() { + assertThat( + Solution().concatenatedDivisibility(intArrayOf(3, 12, 45), 5), + equalTo(intArrayOf(3, 12, 45)), + ) + } + + @Test + fun concatenatedDivisibility2() { + assertThat( + Solution().concatenatedDivisibility(intArrayOf(10, 5), 10), + equalTo(intArrayOf(5, 10)), + ) + } + + @Test + fun concatenatedDivisibility3() { + assertThat( + Solution().concatenatedDivisibility(intArrayOf(1, 2, 3), 5), + equalTo(intArrayOf()), + ) + } +} diff --git a/src/test/kotlin/g3501_3600/s3534_path_existence_queries_in_a_graph_ii/SolutionTest.kt b/src/test/kotlin/g3501_3600/s3534_path_existence_queries_in_a_graph_ii/SolutionTest.kt new file mode 100644 index 000000000..18b42168d --- /dev/null +++ b/src/test/kotlin/g3501_3600/s3534_path_existence_queries_in_a_graph_ii/SolutionTest.kt @@ -0,0 +1,49 @@ +package g3501_3600.s3534_path_existence_queries_in_a_graph_ii + +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Test + +internal class SolutionTest { + @Test + fun pathExistenceQueries() { + assertThat( + Solution() + .pathExistenceQueries( + 5, + intArrayOf(1, 8, 3, 4, 2), + 3, + arrayOf(intArrayOf(0, 3), intArrayOf(2, 4)), + ), + equalTo(intArrayOf(1, 1)), + ) + } + + @Test + fun pathExistenceQueries2() { + assertThat( + Solution() + .pathExistenceQueries( + 5, + intArrayOf(5, 3, 1, 9, 10), + 2, + arrayOf(intArrayOf(0, 1), intArrayOf(0, 2), intArrayOf(2, 3), intArrayOf(4, 3)), + ), + equalTo(intArrayOf(1, 2, -1, 1)), + ) + } + + @Test + fun pathExistenceQueries3() { + assertThat( + Solution() + .pathExistenceQueries( + 3, + intArrayOf(3, 6, 1), + 1, + arrayOf(intArrayOf(0, 0), intArrayOf(0, 1), intArrayOf(1, 2)), + ), + equalTo(intArrayOf(0, -1, -1)), + ) + } +}