diff --git a/src/main/java/g3501_3600/s3527_find_the_most_common_response/Solution.java b/src/main/java/g3501_3600/s3527_find_the_most_common_response/Solution.java new file mode 100644 index 000000000..59f193daa --- /dev/null +++ b/src/main/java/g3501_3600/s3527_find_the_most_common_response/Solution.java @@ -0,0 +1,52 @@ +package g3501_3600.s3527_find_the_most_common_response; + +// #Medium #Array #String #Hash_Table #Counting +// #2025_04_28_Time_94_ms_(100.00%)_Space_211.70_MB_(22.07%) + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Solution { + private boolean compareStrings(String str1, String str2) { + int n = str1.length(); + int m = str2.length(); + int i = 0; + int j = 0; + while (i < n && j < m) { + if (str1.charAt(i) < str2.charAt(j)) { + return true; + } else if (str1.charAt(i) > str2.charAt(j)) { + return false; + } + i++; + j++; + } + return n < m; + } + + public String findCommonResponse(List> responses) { + int n = responses.size(); + Map mp = new HashMap<>(); + String ans = responses.get(0).get(0); + int maxFreq = 0; + for (int row = 0; row < n; row++) { + int m = responses.get(row).size(); + for (int col = 0; col < m; col++) { + String resp = responses.get(row).get(col); + int[] arr = mp.getOrDefault(resp, new int[] {0, -1}); + if (arr[1] != row) { + arr[0]++; + arr[1] = row; + mp.put(resp, arr); + } + if (arr[0] > maxFreq + || !ans.equals(resp) && arr[0] == maxFreq && compareStrings(resp, ans)) { + ans = resp; + maxFreq = arr[0]; + } + } + } + return ans; + } +} diff --git a/src/main/java/g3501_3600/s3527_find_the_most_common_response/readme.md b/src/main/java/g3501_3600/s3527_find_the_most_common_response/readme.md new file mode 100644 index 000000000..cf8a4616f --- /dev/null +++ b/src/main/java/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/java/g3501_3600/s3528_unit_conversion_i/Solution.java b/src/main/java/g3501_3600/s3528_unit_conversion_i/Solution.java new file mode 100644 index 000000000..c7778e015 --- /dev/null +++ b/src/main/java/g3501_3600/s3528_unit_conversion_i/Solution.java @@ -0,0 +1,16 @@ +package g3501_3600.s3528_unit_conversion_i; + +// #Medium #Depth_First_Search #Breadth_First_Search #Graph +// #2025_04_28_Time_3_ms_(99.90%)_Space_127.84_MB_(26.65%) + +public class Solution { + public int[] baseUnitConversions(int[][] conversions) { + int[] arr = new int[conversions.length + 1]; + arr[0] = 1; + for (int[] conversion : conversions) { + long val = ((long) arr[conversion[0]] * conversion[2]) % 1000000007; + arr[conversion[1]] = (int) val; + } + return arr; + } +} diff --git a/src/main/java/g3501_3600/s3528_unit_conversion_i/readme.md b/src/main/java/g3501_3600/s3528_unit_conversion_i/readme.md new file mode 100644 index 000000000..4b0fdcf00 --- /dev/null +++ b/src/main/java/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/java/g3501_3600/s3529_count_cells_in_overlapping_horizontal_and_vertical_substrings/Solution.java b/src/main/java/g3501_3600/s3529_count_cells_in_overlapping_horizontal_and_vertical_substrings/Solution.java new file mode 100644 index 000000000..83043565e --- /dev/null +++ b/src/main/java/g3501_3600/s3529_count_cells_in_overlapping_horizontal_and_vertical_substrings/Solution.java @@ -0,0 +1,85 @@ +package g3501_3600.s3529_count_cells_in_overlapping_horizontal_and_vertical_substrings; + +// #Medium #Array #String #Matrix #Hash_Function #String_Matching #Rolling_Hash +// #2025_04_28_Time_33_ms_(100.00%)_Space_62.71_MB_(100.00%) + +public class Solution { + public int countCells(char[][] grid, String pattern) { + int k = pattern.length(); + int[] lps = makeLps(pattern); + int m = grid.length; + int n = grid[0].length; + int[][] horiPats = new int[m][n]; + int[][] vertPats = new int[m][n]; + int i = 0; + int j = 0; + while (i < m * n) { + if (grid[i / n][i % n] == pattern.charAt(j)) { + i++; + if (++j == k) { + int d = i - j; + horiPats[d / n][d % n]++; + if (i < m * n) { + horiPats[i / n][i % n]--; + } + 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.charAt(j)) { + i++; + if (++j == k) { + int d = i - j; + vertPats[d % m][d / m]++; + if (i < m * n) { + vertPats[i % m][i / m]--; + } + j = lps[j - 1]; + } + } else if (j != 0) { + j = lps[j - 1]; + } else { + i++; + } + } + for (i = 1; i < m * n; i++) { + vertPats[i % m][i / m] += vertPats[(i - 1) % m][(i - 1) / m]; + horiPats[i / n][i % n] += horiPats[(i - 1) / n][(i - 1) % n]; + } + int res = 0; + for (i = 0; i < m; i++) { + for (j = 0; j < n; j++) { + if (horiPats[i][j] > 0 && vertPats[i][j] > 0) { + res++; + } + } + } + return res; + } + + private int[] makeLps(String pattern) { + int n = pattern.length(); + int[] lps = new int[n]; + int len = 0; + int i = 1; + lps[0] = 0; + while (i < n) { + if (pattern.charAt(i) == pattern.charAt(len)) { + lps[i++] = ++len; + } else if (len != 0) { + len = lps[len - 1]; + } else { + lps[i++] = 0; + } + } + return lps; + } +} diff --git a/src/main/java/g3501_3600/s3529_count_cells_in_overlapping_horizontal_and_vertical_substrings/readme.md b/src/main/java/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/java/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/java/g3501_3600/s3530_maximum_profit_from_valid_topological_order_in_dag/Solution.java b/src/main/java/g3501_3600/s3530_maximum_profit_from_valid_topological_order_in_dag/Solution.java new file mode 100644 index 000000000..a494f914e --- /dev/null +++ b/src/main/java/g3501_3600/s3530_maximum_profit_from_valid_topological_order_in_dag/Solution.java @@ -0,0 +1,58 @@ +package g3501_3600.s3530_maximum_profit_from_valid_topological_order_in_dag; + +// #Hard #Array #Dynamic_Programming #Bit_Manipulation #Graph #Bitmask #Topological_Sort +// #2025_04_28_Time_1927_ms_(100.00%)_Space_66.86_MB_(100.00%) + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class Solution { + private int helper( + int mask, + int pos, + int[] inDegree, + List> adj, + int[] score, + int[] dp, + int n) { + if (mask == (1 << n) - 1) { + return 0; + } + if (dp[mask] != -1) { + return dp[mask]; + } + int res = 0; + for (int i = 0; i < n; i++) { + if ((mask & (1 << i)) == 0 && inDegree[i] == 0) { + for (int ng : adj.get(i)) { + inDegree[ng]--; + } + int val = + pos * score[i] + + helper(mask | (1 << i), pos + 1, inDegree, adj, score, dp, n); + res = Math.max(res, val); + for (int ng : adj.get(i)) { + inDegree[ng]++; + } + } + } + dp[mask] = res; + return res; + } + + public int maxProfit(int n, int[][] edges, int[] score) { + List> adj = new ArrayList<>(); + for (int i = 0; i < n; i++) { + adj.add(new ArrayList<>()); + } + int[] inDegree = new int[n]; + for (int[] e : edges) { + adj.get(e[0]).add(e[1]); + inDegree[e[1]]++; + } + int[] dp = new int[1 << n]; + Arrays.fill(dp, -1); + return helper(0, 1, inDegree, adj, score, dp, n); + } +} diff --git a/src/main/java/g3501_3600/s3530_maximum_profit_from_valid_topological_order_in_dag/readme.md b/src/main/java/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/java/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/java/g3501_3600/s3531_count_covered_buildings/Solution.java b/src/main/java/g3501_3600/s3531_count_covered_buildings/Solution.java new file mode 100644 index 000000000..e5d7f6d22 --- /dev/null +++ b/src/main/java/g3501_3600/s3531_count_covered_buildings/Solution.java @@ -0,0 +1,37 @@ +package g3501_3600.s3531_count_covered_buildings; + +// #Medium #Array #Hash_Table #Sorting #2025_04_28_Time_12_ms_(100.00%)_Space_111.46_MB_(100.00%) + +import java.util.Arrays; + +public class Solution { + private int helper(int[][] buildings, int n) { + int[] minRow = new int[n + 1]; + int[] maxRow = new int[n + 1]; + int[] minCol = new int[n + 1]; + int[] maxCol = new int[n + 1]; + Arrays.fill(minRow, n + 1); + Arrays.fill(minCol, n + 1); + for (int[] b : buildings) { + int x = b[0]; + int y = b[1]; + minRow[x] = Math.min(minRow[x], y); + maxRow[x] = Math.max(maxRow[x], y); + minCol[y] = Math.min(minCol[y], x); + maxCol[y] = Math.max(maxCol[y], x); + } + int ans = 0; + for (int[] arr : buildings) { + int x = arr[0]; + int y = arr[1]; + if (minRow[x] < y && maxRow[x] > y && minCol[y] < x && maxCol[y] > x) { + ans++; + } + } + return ans; + } + + public int countCoveredBuildings(int n, int[][] buildings) { + return helper(buildings, n); + } +} diff --git a/src/main/java/g3501_3600/s3531_count_covered_buildings/readme.md b/src/main/java/g3501_3600/s3531_count_covered_buildings/readme.md new file mode 100644 index 000000000..f491af619 --- /dev/null +++ b/src/main/java/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/java/g3501_3600/s3532_path_existence_queries_in_a_graph_i/Solution.java b/src/main/java/g3501_3600/s3532_path_existence_queries_in_a_graph_i/Solution.java new file mode 100644 index 000000000..c61322bae --- /dev/null +++ b/src/main/java/g3501_3600/s3532_path_existence_queries_in_a_graph_i/Solution.java @@ -0,0 +1,27 @@ +package g3501_3600.s3532_path_existence_queries_in_a_graph_i; + +// #Medium #Array #Binary_Search #Graph #Union_Find +// #2025_04_28_Time_3_ms_(100.00%)_Space_77.82_MB_(100.00%) + +public class Solution { + public boolean[] pathExistenceQueries(int n, int[] nums, int maxDiff, int[][] queries) { + int[] comp = new int[n]; + int compId = 0; + comp[0] = compId; + for (int i = 1; i < n; i++) { + if (nums[i] - nums[i - 1] <= maxDiff) { + comp[i] = compId; + } else { + compId++; + comp[i] = compId; + } + } + boolean[] ans = new boolean[queries.length]; + for (int i = 0; i < queries.length; i++) { + int x = queries[i][0]; + int y = queries[i][1]; + ans[i] = (comp[x] == comp[y]); + } + return ans; + } +} diff --git a/src/main/java/g3501_3600/s3532_path_existence_queries_in_a_graph_i/readme.md b/src/main/java/g3501_3600/s3532_path_existence_queries_in_a_graph_i/readme.md new file mode 100644 index 000000000..ba1c82def --- /dev/null +++ b/src/main/java/g3501_3600/s3532_path_existence_queries_in_a_graph_i/readme.md @@ -0,0 +1,53 @@ +3532\. Path Existence Queries in a Graph I + +Medium + +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` sorted in **non-decreasing** order, 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], 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/java/g3501_3600/s3533_concatenated_divisibility/Solution.java b/src/main/java/g3501_3600/s3533_concatenated_divisibility/Solution.java new file mode 100644 index 000000000..e3caad557 --- /dev/null +++ b/src/main/java/g3501_3600/s3533_concatenated_divisibility/Solution.java @@ -0,0 +1,66 @@ +package g3501_3600.s3533_concatenated_divisibility; + +// #Hard #Array #Dynamic_Programming #Bit_Manipulation #Bitmask +// #2025_04_28_Time_14_ms_(100.00%)_Space_45.98_MB_(100.00%) + +import java.util.Arrays; + +@SuppressWarnings("java:S107") +public class Solution { + public int[] concatenatedDivisibility(int[] nums, int k) { + Arrays.sort(nums); + int digits = 0; + int n = nums.length; + int[] digCnt = new int[n]; + for (int i = 0; i < n; i++) { + int num = nums[i]; + digits++; + digCnt[i]++; + while (num >= 10) { + digits++; + digCnt[i]++; + num /= 10; + } + } + int[] pow10 = new int[digits + 1]; + pow10[0] = 1; + for (int i = 1; i <= digits; i++) { + pow10[i] = (pow10[i - 1] * 10) % k; + } + int[] res = new int[n]; + return dfs(0, 0, k, digCnt, nums, pow10, new boolean[1 << n][k], 0, res, n) + ? res + : new int[0]; + } + + private boolean dfs( + int mask, + int residue, + int k, + int[] digCnt, + int[] nums, + int[] pow10, + boolean[][] visited, + int ansIdx, + int[] ans, + int n) { + if (ansIdx == n) { + return residue == 0; + } + if (visited[mask][residue]) { + return false; + } + for (int i = 0, bit = 1; i < n; i++, bit <<= 1) { + if ((mask & bit) == bit) { + continue; + } + int newResidue = (residue * pow10[digCnt[i]] + nums[i]) % k; + ans[ansIdx] = nums[i]; + if (dfs(mask | bit, newResidue, k, digCnt, nums, pow10, visited, ansIdx + 1, ans, n)) { + return true; + } + } + visited[mask][residue] = true; + return false; + } +} diff --git a/src/main/java/g3501_3600/s3533_concatenated_divisibility/readme.md b/src/main/java/g3501_3600/s3533_concatenated_divisibility/readme.md new file mode 100644 index 000000000..789cc1d9f --- /dev/null +++ b/src/main/java/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/java/g3501_3600/s3534_path_existence_queries_in_a_graph_ii/Solution.java b/src/main/java/g3501_3600/s3534_path_existence_queries_in_a_graph_ii/Solution.java new file mode 100644 index 000000000..f16882be2 --- /dev/null +++ b/src/main/java/g3501_3600/s3534_path_existence_queries_in_a_graph_ii/Solution.java @@ -0,0 +1,86 @@ +package g3501_3600.s3534_path_existence_queries_in_a_graph_ii; + +// #Hard #Array #Sorting #Greedy #Binary_Search #Graph +// #2025_04_28_Time_84_ms_(100.00%)_Space_81.21_MB_(100.00%) + +import java.util.Arrays; + +@SuppressWarnings({"java:S135", "java:S6541"}) +public class Solution { + public int[] pathExistenceQueries(int n, int[] nums, int maxDiff, int[][] queries) { + int[] position = new int[n]; + int[] values = new int[n]; + Integer[] sortedIndices = new Integer[n]; + for (int i = 0; i < n; i++) { + sortedIndices[i] = i; + } + Arrays.sort(sortedIndices, (a, b) -> Integer.compare(nums[a], nums[b])); + for (int i = 0; i < n; i++) { + position[sortedIndices[i]] = i; + values[i] = nums[sortedIndices[i]]; + } + int[] reachableIndex = new int[n]; + int j = 0; + for (int i = 0; i < n; i++) { + if (j < i) { + j = i; + } + while (j + 1 < n && values[j + 1] - values[i] <= maxDiff) { + j++; + } + reachableIndex[i] = j; + } + int maxLog = 1; + while ((1 << maxLog) < n) { + maxLog++; + } + int[][] upTable = new int[maxLog][n]; + upTable[0] = reachableIndex.clone(); + for (int k = 1; k < maxLog; k++) { + for (int i = 0; i < n; i++) { + upTable[k][i] = upTable[k - 1][upTable[k - 1][i]]; + } + } + int[] results = new int[queries.length]; + for (int idx = 0; idx < queries.length; idx++) { + int start = queries[idx][0]; + int end = queries[idx][1]; + if (start == end) { + results[idx] = 0; + continue; + } + int startPos = position[start]; + int endPos = position[end]; + if (startPos > endPos) { + int temp = startPos; + startPos = endPos; + endPos = temp; + } + if (Math.abs(nums[start] - nums[end]) <= maxDiff) { + results[idx] = 1; + continue; + } + if (reachableIndex[startPos] < endPos) { + int current = startPos; + int jumpCount = 0; + for (int k = maxLog - 1; k >= 0; k--) { + if (upTable[k][current] < endPos) { + if (upTable[k][current] == current) { + break; + } + current = upTable[k][current]; + jumpCount += 1 << k; + } + } + if (reachableIndex[current] >= endPos) { + results[idx] = jumpCount + 1; + } else { + results[idx] = -1; + } + } else { + results[idx] = 1; + } + } + return results; + } +} diff --git a/src/main/java/g3501_3600/s3534_path_existence_queries_in_a_graph_ii/readme.md b/src/main/java/g3501_3600/s3534_path_existence_queries_in_a_graph_ii/readme.md new file mode 100644 index 000000000..4554c5084 --- /dev/null +++ b/src/main/java/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/java/g3501_3600/s3527_find_the_most_common_response/SolutionTest.java b/src/test/java/g3501_3600/s3527_find_the_most_common_response/SolutionTest.java new file mode 100644 index 000000000..ee9124daf --- /dev/null +++ b/src/test/java/g3501_3600/s3527_find_the_most_common_response/SolutionTest.java @@ -0,0 +1,49 @@ +package g3501_3600.s3527_find_the_most_common_response; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import java.util.List; +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void findCommonResponse() { + assertThat( + new Solution() + .findCommonResponse( + List.of( + List.of("good", "ok", "good", "ok"), + List.of("ok", "bad", "good", "ok", "ok"), + List.of("good"), + List.of("bad"))), + equalTo("good")); + } + + @Test + void findCommonResponse2() { + assertThat( + new Solution() + .findCommonResponse( + List.of( + List.of("good", "ok", "good"), + List.of("ok", "bad"), + List.of("bad", "notsure"), + List.of("great", "good"))), + equalTo("bad")); + } + + @Test + void findCommonResponse3() { + assertThat( + new Solution() + .findCommonResponse( + List.of( + List.of("fed", "vgdb", "w", "zs", "fed"), + List.of("f", "cz", "pah", "gj", "rpxr", "ugyi"), + List.of("t", "oja", "c"), + List.of("ni", "fed", "mcox", "a", "f", "ni", "g"), + List.of("ybk", "xght", "jje"))), + equalTo("f")); + } +} diff --git a/src/test/java/g3501_3600/s3528_unit_conversion_i/SolutionTest.java b/src/test/java/g3501_3600/s3528_unit_conversion_i/SolutionTest.java new file mode 100644 index 000000000..00e901645 --- /dev/null +++ b/src/test/java/g3501_3600/s3528_unit_conversion_i/SolutionTest.java @@ -0,0 +1,27 @@ +package g3501_3600.s3528_unit_conversion_i; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void baseUnitConversions() { + assertThat( + new Solution().baseUnitConversions(new int[][] {{0, 1, 2}, {1, 2, 3}}), + equalTo(new int[] {1, 2, 6})); + } + + @Test + void baseUnitConversions2() { + assertThat( + new Solution() + .baseUnitConversions( + new int[][] { + {0, 1, 2}, {0, 2, 3}, {1, 3, 4}, {1, 4, 5}, {2, 5, 2}, + {4, 6, 3}, {5, 7, 4} + }), + equalTo(new int[] {1, 2, 3, 8, 10, 6, 30, 24})); + } +} diff --git a/src/test/java/g3501_3600/s3529_count_cells_in_overlapping_horizontal_and_vertical_substrings/SolutionTest.java b/src/test/java/g3501_3600/s3529_count_cells_in_overlapping_horizontal_and_vertical_substrings/SolutionTest.java new file mode 100644 index 000000000..267fc705c --- /dev/null +++ b/src/test/java/g3501_3600/s3529_count_cells_in_overlapping_horizontal_and_vertical_substrings/SolutionTest.java @@ -0,0 +1,44 @@ +package g3501_3600.s3529_count_cells_in_overlapping_horizontal_and_vertical_substrings; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void countCells() { + assertThat( + new Solution() + .countCells( + new char[][] { + {'a', 'a', 'c', 'c'}, + {'b', 'b', 'b', 'c'}, + {'a', 'a', 'b', 'a'}, + {'c', 'a', 'a', 'c'}, + {'a', 'a', 'c', 'c'} + }, + "abaca"), + equalTo(1)); + } + + @Test + void countCells2() { + assertThat( + new Solution() + .countCells( + new char[][] { + {'c', 'a', 'a', 'a'}, + {'a', 'a', 'b', 'a'}, + {'b', 'b', 'a', 'a'}, + {'a', 'a', 'b', 'a'} + }, + "aba"), + equalTo(4)); + } + + @Test + void countCells3() { + assertThat(new Solution().countCells(new char[][] {{'a'}}, "a"), equalTo(1)); + } +} diff --git a/src/test/java/g3501_3600/s3530_maximum_profit_from_valid_topological_order_in_dag/SolutionTest.java b/src/test/java/g3501_3600/s3530_maximum_profit_from_valid_topological_order_in_dag/SolutionTest.java new file mode 100644 index 000000000..d18ade1de --- /dev/null +++ b/src/test/java/g3501_3600/s3530_maximum_profit_from_valid_topological_order_in_dag/SolutionTest.java @@ -0,0 +1,20 @@ +package g3501_3600.s3530_maximum_profit_from_valid_topological_order_in_dag; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void maxProfit() { + assertThat(new Solution().maxProfit(2, new int[][] {{0, 1}}, new int[] {2, 3}), equalTo(8)); + } + + @Test + void maxProfit2() { + assertThat( + new Solution().maxProfit(3, new int[][] {{0, 1}, {0, 2}}, new int[] {1, 6, 3}), + equalTo(25)); + } +} diff --git a/src/test/java/g3501_3600/s3531_count_covered_buildings/SolutionTest.java b/src/test/java/g3501_3600/s3531_count_covered_buildings/SolutionTest.java new file mode 100644 index 000000000..4cc79518f --- /dev/null +++ b/src/test/java/g3501_3600/s3531_count_covered_buildings/SolutionTest.java @@ -0,0 +1,34 @@ +package g3501_3600.s3531_count_covered_buildings; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void countCoveredBuildings() { + assertThat( + new Solution() + .countCoveredBuildings( + 3, new int[][] {{1, 2}, {2, 2}, {3, 2}, {2, 1}, {2, 3}}), + equalTo(1)); + } + + @Test + void countCoveredBuildings2() { + assertThat( + new Solution() + .countCoveredBuildings(3, new int[][] {{1, 1}, {1, 2}, {2, 1}, {2, 2}}), + equalTo(0)); + } + + @Test + void countCoveredBuildings3() { + assertThat( + new Solution() + .countCoveredBuildings( + 5, new int[][] {{1, 3}, {3, 2}, {3, 3}, {3, 5}, {5, 3}}), + equalTo(1)); + } +} diff --git a/src/test/java/g3501_3600/s3532_path_existence_queries_in_a_graph_i/SolutionTest.java b/src/test/java/g3501_3600/s3532_path_existence_queries_in_a_graph_i/SolutionTest.java new file mode 100644 index 000000000..fa730b5b7 --- /dev/null +++ b/src/test/java/g3501_3600/s3532_path_existence_queries_in_a_graph_i/SolutionTest.java @@ -0,0 +1,28 @@ +package g3501_3600.s3532_path_existence_queries_in_a_graph_i; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void pathExistenceQueries() { + assertThat( + new Solution() + .pathExistenceQueries(2, new int[] {1, 3}, 1, new int[][] {{0, 0}, {0, 1}}), + equalTo(new boolean[] {true, false})); + } + + @Test + void pathExistenceQueries2() { + assertThat( + new Solution() + .pathExistenceQueries( + 4, + new int[] {2, 5, 6, 8}, + 2, + new int[][] {{0, 1}, {0, 2}, {1, 3}, {2, 3}}), + equalTo(new boolean[] {false, false, true, true})); + } +} diff --git a/src/test/java/g3501_3600/s3533_concatenated_divisibility/SolutionTest.java b/src/test/java/g3501_3600/s3533_concatenated_divisibility/SolutionTest.java new file mode 100644 index 000000000..a2c44dc09 --- /dev/null +++ b/src/test/java/g3501_3600/s3533_concatenated_divisibility/SolutionTest.java @@ -0,0 +1,29 @@ +package g3501_3600.s3533_concatenated_divisibility; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void concatenatedDivisibility() { + assertThat( + new Solution().concatenatedDivisibility(new int[] {3, 12, 45}, 5), + equalTo(new int[] {3, 12, 45})); + } + + @Test + void concatenatedDivisibility2() { + assertThat( + new Solution().concatenatedDivisibility(new int[] {10, 5}, 10), + equalTo(new int[] {5, 10})); + } + + @Test + void concatenatedDivisibility3() { + assertThat( + new Solution().concatenatedDivisibility(new int[] {1, 2, 3}, 5), + equalTo(new int[] {})); + } +} diff --git a/src/test/java/g3501_3600/s3534_path_existence_queries_in_a_graph_ii/SolutionTest.java b/src/test/java/g3501_3600/s3534_path_existence_queries_in_a_graph_ii/SolutionTest.java new file mode 100644 index 000000000..30888b2ec --- /dev/null +++ b/src/test/java/g3501_3600/s3534_path_existence_queries_in_a_graph_ii/SolutionTest.java @@ -0,0 +1,38 @@ +package g3501_3600.s3534_path_existence_queries_in_a_graph_ii; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void pathExistenceQueries() { + assertThat( + new Solution() + .pathExistenceQueries( + 5, new int[] {1, 8, 3, 4, 2}, 3, new int[][] {{0, 3}, {2, 4}}), + equalTo(new int[] {1, 1})); + } + + @Test + void pathExistenceQueries2() { + assertThat( + new Solution() + .pathExistenceQueries( + 5, + new int[] {5, 3, 1, 9, 10}, + 2, + new int[][] {{0, 1}, {0, 2}, {2, 3}, {4, 3}}), + equalTo(new int[] {1, 2, -1, 1})); + } + + @Test + void pathExistenceQueries3() { + assertThat( + new Solution() + .pathExistenceQueries( + 3, new int[] {3, 6, 1}, 1, new int[][] {{0, 0}, {0, 1}, {1, 2}}), + equalTo(new int[] {0, -1, -1})); + } +}