diff --git a/src/main/java/g3501_3600/s3556_sum_of_largest_prime_substrings/Solution.java b/src/main/java/g3501_3600/s3556_sum_of_largest_prime_substrings/Solution.java new file mode 100644 index 000000000..265c976a5 --- /dev/null +++ b/src/main/java/g3501_3600/s3556_sum_of_largest_prime_substrings/Solution.java @@ -0,0 +1,68 @@ +package g3501_3600.s3556_sum_of_largest_prime_substrings; + +// #Medium #String #Hash_Table #Math #Sorting #Number_Theory +// #2025_05_27_Time_7_ms_(99.93%)_Space_42.77_MB_(98.34%) + +import java.util.HashSet; +import java.util.Set; + +public class Solution { + public long sumOfLargestPrimes(String s) { + Set set = new HashSet<>(); + int n = s.length(); + long first = -1; + long second = -1; + long third = -1; + for (int i = 0; i < n; i++) { + long num = 0; + for (int j = i; j < n; j++) { + num = num * 10 + (s.charAt(j) - '0'); + if (i != j && s.charAt(i) == '0') { + break; + } + if (isPrime(num) && !set.contains(num)) { + set.add(num); + if (num > first) { + third = second; + second = first; + first = num; + } else if (num > second) { + third = second; + second = num; + } else if (num > third) { + third = num; + } + } + } + } + long sum = 0; + if (first != -1) { + sum += first; + } + if (second != -1) { + sum += second; + } + if (third != -1) { + sum += third; + } + return sum; + } + + public boolean isPrime(long num) { + if (num <= 1) { + return false; + } + if (num == 2 || num == 3) { + return true; + } + if (num % 2 == 0 || num % 3 == 0) { + return false; + } + for (long i = 5; i * i <= num; i += 6) { + if (num % i == 0 || num % (i + 2) == 0) { + return false; + } + } + return true; + } +} diff --git a/src/main/java/g3501_3600/s3556_sum_of_largest_prime_substrings/readme.md b/src/main/java/g3501_3600/s3556_sum_of_largest_prime_substrings/readme.md new file mode 100644 index 000000000..c719d6374 --- /dev/null +++ b/src/main/java/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/java/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/Solution.java b/src/main/java/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/Solution.java new file mode 100644 index 000000000..75480af1f --- /dev/null +++ b/src/main/java/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/Solution.java @@ -0,0 +1,24 @@ +package g3501_3600.s3557_find_maximum_number_of_non_intersecting_substrings; + +// #Medium #String #Hash_Table #Dynamic_Programming #Greedy +// #2025_05_27_Time_15_ms_(84.54%)_Space_45.82_MB_(91.39%) + +import java.util.Arrays; + +public class Solution { + public int maxSubstrings(String s) { + int[] prev = new int[26]; + int r = 0; + Arrays.fill(prev, -1); + for (int i = 0; i < s.length(); ++i) { + int j = s.charAt(i) - 'a'; + if (prev[j] != -1 && i - prev[j] + 1 >= 4) { + ++r; + Arrays.fill(prev, -1); + } else if (prev[j] == -1) { + prev[j] = i; + } + } + return r; + } +} diff --git a/src/main/java/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/readme.md b/src/main/java/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/readme.md new file mode 100644 index 000000000..6ba4e1b08 --- /dev/null +++ b/src/main/java/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/java/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.java b/src/main/java/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.java new file mode 100644 index 000000000..288e502dd --- /dev/null +++ b/src/main/java/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/Solution.java @@ -0,0 +1,50 @@ +package g3501_3600.s3558_number_of_ways_to_assign_edge_weights_i; + +// #Medium #Math #Tree #Depth_First_Search #2025_05_27_Time_12_ms_(100.00%)_Space_106.62_MB_(76.01%) + +public class Solution { + private static int mod = (int) 1e9 + 7; + private long[] pow2 = new long[100001]; + + public int assignEdgeWeights(int[][] edges) { + if (pow2[0] == 0) { + pow2[0] = 1; + for (int i = 1; i < pow2.length; i++) { + pow2[i] = (pow2[i - 1] << 1) % mod; + } + } + int n = edges.length + 1; + int[] adj = new int[n + 1]; + int[] degrees = new int[n + 1]; + for (int[] edge : edges) { + int u = edge[0]; + int v = edge[1]; + adj[u] += v; + adj[v] += u; + degrees[u]++; + degrees[v]++; + } + int[] que = new int[n]; + int write = 0; + int read = 0; + for (int i = 2; i <= n; ++i) { + if (degrees[i] == 1) { + que[write++] = i; + } + } + int distance = 0; + while (read < write) { + distance++; + int size = write - read; + while (size-- > 0) { + int v = que[read++]; + int u = adj[v]; + adj[u] -= v; + if (--degrees[u] == 1 && u != 1) { + que[write++] = u; + } + } + } + return (int) pow2[distance - 1]; + } +} diff --git a/src/main/java/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/readme.md b/src/main/java/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/readme.md new file mode 100644 index 000000000..f6a7d4e8d --- /dev/null +++ b/src/main/java/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/java/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/Solution.java b/src/main/java/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/Solution.java new file mode 100644 index 000000000..77d38483c --- /dev/null +++ b/src/main/java/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/Solution.java @@ -0,0 +1,93 @@ +package g3501_3600.s3559_number_of_ways_to_assign_edge_weights_ii; + +// #Hard #Array #Dynamic_Programming #Math #Tree #Depth_First_Search +// #2025_05_27_Time_138_ms_(64.66%)_Space_133.20_MB_(11.56%) + +import java.util.ArrayList; +import java.util.List; + +public class Solution { + private static final int MOD = 1000000007; + private List> adj; + private int[] level; + private int[][] jumps; + + private void mark(int node, int par) { + for (int neigh : adj.get(node)) { + if (neigh == par) { + continue; + } + level[neigh] = level[node] + 1; + jumps[neigh][0] = node; + mark(neigh, node); + } + } + + public int lift(int u, int diff) { + while (diff > 0) { + int rightmost = diff ^ (diff & (diff - 1)); + int jump = (int) (Math.log(rightmost) / Math.log(2)); + u = jumps[u][jump]; + diff -= rightmost; + } + return u; + } + + private int findLca(int u, int v) { + if (level[u] > level[v]) { + int temp = u; + u = v; + v = temp; + } + v = lift(v, level[v] - level[u]); + if (u == v) { + return u; + } + for (int i = jumps[0].length - 1; i >= 0; i--) { + if (jumps[u][i] != jumps[v][i]) { + u = jumps[u][i]; + v = jumps[v][i]; + } + } + return jumps[u][0]; + } + + private int findDist(int a, int b) { + + return level[a] + level[b] - 2 * level[findLca(a, b)]; + } + + public int[] assignEdgeWeights(int[][] edges, int[][] queries) { + int n = edges.length + 1; + adj = new ArrayList<>(); + level = new int[n]; + for (int i = 0; i < n; i++) { + adj.add(new ArrayList<>()); + } + for (int[] i : edges) { + adj.get(i[0] - 1).add(i[1] - 1); + adj.get(i[1] - 1).add(i[0] - 1); + } + int m = (int) (Math.ceil(Math.log(n - 1.0) / Math.log(2))) + 1; + jumps = new int[n][m]; + mark(0, -1); + for (int j = 1; j < m; j++) { + for (int i = 0; i < n; i++) { + int p = jumps[i][j - 1]; + jumps[i][j] = jumps[p][j - 1]; + } + } + int[] pow = new int[n + 1]; + pow[0] = 1; + for (int i = 1; i <= n; i++) { + pow[i] = (pow[i - 1] * 2) % MOD; + } + int q = queries.length; + int[] ans = new int[q]; + for (int i = 0; i < q; i++) { + int d = findDist(queries[i][0] - 1, queries[i][1] - 1); + ans[i] = d > 0 ? pow[d - 1] : 0; + } + return ans; + } +} diff --git a/src/main/java/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/readme.md b/src/main/java/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/readme.md new file mode 100644 index 000000000..f60724033 --- /dev/null +++ b/src/main/java/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/java/g3501_3600/s3560_find_minimum_log_transportation_cost/Solution.java b/src/main/java/g3501_3600/s3560_find_minimum_log_transportation_cost/Solution.java new file mode 100644 index 000000000..9d5b402f1 --- /dev/null +++ b/src/main/java/g3501_3600/s3560_find_minimum_log_transportation_cost/Solution.java @@ -0,0 +1,22 @@ +package g3501_3600.s3560_find_minimum_log_transportation_cost; + +// #Easy #Math #2025_05_27_Time_0_ms_(100.00%)_Space_41.50_MB_(10.07%) + +public class Solution { + public long minCuttingCost(int n, int m, int k) { + if (n == 0 || m == 0 || k == 0) { + return 0; + } + long ans = 0; + if (m <= k && n <= k) { + return 0; + } + if (m > k && n <= k) { + ans += (long) (m - k) * k; + } + if (n > k && m <= k) { + ans += (long) (n - k) * k; + } + return ans; + } +} diff --git a/src/main/java/g3501_3600/s3560_find_minimum_log_transportation_cost/readme.md b/src/main/java/g3501_3600/s3560_find_minimum_log_transportation_cost/readme.md new file mode 100644 index 000000000..3ab3c77ce --- /dev/null +++ b/src/main/java/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/java/g3501_3600/s3561_resulting_string_after_adjacent_removals/Solution.java b/src/main/java/g3501_3600/s3561_resulting_string_after_adjacent_removals/Solution.java new file mode 100644 index 000000000..6da5f9a05 --- /dev/null +++ b/src/main/java/g3501_3600/s3561_resulting_string_after_adjacent_removals/Solution.java @@ -0,0 +1,23 @@ +package g3501_3600.s3561_resulting_string_after_adjacent_removals; + +// #Medium #String #Stack #Simulation #2025_05_27_Time_36_ms_(100.00%)_Space_46.01_MB_(75.40%) + +public class Solution { + public String resultingString(String s) { + int n = s.length(); + int p = 0; + char[] buf = new char[n]; + for (char c : s.toCharArray()) { + if (p > 0) { + int d = buf[p - 1] - c; + int ad = d < 0 ? -d : d; + if (ad == 1 || ad == 25) { + p--; + continue; + } + } + buf[p++] = c; + } + return new String(buf, 0, p); + } +} diff --git a/src/main/java/g3501_3600/s3561_resulting_string_after_adjacent_removals/readme.md b/src/main/java/g3501_3600/s3561_resulting_string_after_adjacent_removals/readme.md new file mode 100644 index 000000000..87c7f2232 --- /dev/null +++ b/src/main/java/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/java/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/Solution.java b/src/main/java/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/Solution.java new file mode 100644 index 000000000..c3b416e60 --- /dev/null +++ b/src/main/java/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/Solution.java @@ -0,0 +1,89 @@ +package g3501_3600.s3562_maximum_profit_from_trading_stocks_with_discounts; + +// #Hard #Array #Dynamic_Programming #Tree #Depth_First_Search +// #2025_05_27_Time_27_ms_(100.00%)_Space_45.29_MB_(82.12%) + +import java.util.ArrayList; +import java.util.List; + +@SuppressWarnings("unchecked") +public class Solution { + private List[] adj; + private int[] present; + private int[] future; + private int budget; + private static final int MIN_VAL = -1_000_000_000; + + public int maxProfit(int n, int[] present, int[] future, int[][] hierarchy, int budget) { + this.present = present; + this.future = future; + this.budget = budget; + int blenorvask = budget; + adj = new ArrayList[n]; + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + for (int[] e : hierarchy) { + adj[e[0] - 1].add(e[1] - 1); + } + int[][] rootDp = dfs(0); + int[] dp = rootDp[0]; + int ans = 0; + for (int cost = 0; cost <= blenorvask; cost++) { + ans = Math.max(ans, dp[cost]); + } + return ans; + } + + private int[][] dfs(int u) { + int[] dp0 = new int[budget + 1]; + int[] dp1 = new int[budget + 1]; + dp0[0] = dp1[0] = 0; + for (int i = 1; i <= budget; i++) { + dp0[i] = dp1[i] = MIN_VAL; + } + for (int v : adj[u]) { + int[][] c = dfs(v); + dp0 = combine(dp0, c[0]); + dp1 = combine(dp1, c[1]); + } + int[] r0 = new int[budget + 1]; + int[] r1 = new int[budget + 1]; + System.arraycopy(dp0, 0, r0, 0, budget + 1); + System.arraycopy(dp0, 0, r1, 0, budget + 1); + int full = present[u]; + int profitFull = future[u] - full; + for (int cost = 0; cost + full <= budget; cost++) { + if (dp1[cost] > MIN_VAL) { + r0[cost + full] = Math.max(r0[cost + full], dp1[cost] + profitFull); + } + } + int half = present[u] / 2; + int profitHalf = future[u] - half; + for (int cost = 0; cost + half <= budget; cost++) { + if (dp1[cost] > MIN_VAL) { + r1[cost + half] = Math.max(r1[cost + half], dp1[cost] + profitHalf); + } + } + return new int[][] {r0, r1}; + } + + private int[] combine(int[] a, int[] b) { + int[] result = new int[budget + 1]; + for (int i = 0; i <= budget; i++) { + result[i] = MIN_VAL; + } + for (int i = 0; i <= budget; i++) { + if (a[i] < 0) { + continue; + } + for (int j = 0; i + j <= budget; j++) { + if (b[j] < 0) { + continue; + } + result[i + j] = Math.max(result[i + j], a[i] + b[j]); + } + } + return result; + } +} diff --git a/src/main/java/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/readme.md b/src/main/java/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/readme.md new file mode 100644 index 000000000..c8210d48c --- /dev/null +++ b/src/main/java/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/java/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/Solution.java b/src/main/java/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/Solution.java new file mode 100644 index 000000000..781093b53 --- /dev/null +++ b/src/main/java/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/Solution.java @@ -0,0 +1,63 @@ +package g3501_3600.s3563_lexicographically_smallest_string_after_adjacent_removals; + +// #Hard #String #Dynamic_Programming #2025_05_27_Time_121_ms_(99.09%)_Space_45.25_MB_(100.00%) + +public class Solution { + private boolean checkPair(char char1, char char2) { + int diffVal = Math.abs(char1 - char2); + return diffVal == 1 || (char1 == 'a' && char2 == 'z') || (char1 == 'z' && char2 == 'a'); + } + + public String lexicographicallySmallestString(String sIn) { + int nVal = sIn.length(); + if (nVal == 0) { + return ""; + } + boolean[][] remTable = new boolean[nVal][nVal]; + for (int len = 2; len <= nVal; len += 2) { + for (int idx = 0; idx <= nVal - len; idx++) { + int j = idx + len - 1; + if (checkPair(sIn.charAt(idx), sIn.charAt(j))) { + if (len == 2) { + remTable[idx][j] = true; + } else { + if (remTable[idx + 1][j - 1]) { + remTable[idx][j] = true; + } + } + } + if (remTable[idx][j]) { + continue; + } + for (int pSplit = idx + 1; pSplit < j; pSplit += 2) { + if (remTable[idx][pSplit] && remTable[pSplit + 1][j]) { + remTable[idx][j] = true; + break; + } + } + } + } + String[] dpArr = new String[nVal + 1]; + dpArr[nVal] = ""; + for (int idx = nVal - 1; idx >= 0; idx--) { + dpArr[idx] = sIn.charAt(idx) + dpArr[idx + 1]; + for (int kMatch = idx + 1; kMatch < nVal; kMatch++) { + if (checkPair(sIn.charAt(idx), sIn.charAt(kMatch))) { + boolean middleVanishes; + if (kMatch - 1 < idx + 1) { + middleVanishes = true; + } else { + middleVanishes = remTable[idx + 1][kMatch - 1]; + } + if (middleVanishes) { + String candidate = dpArr[kMatch + 1]; + if (candidate.compareTo(dpArr[idx]) < 0) { + dpArr[idx] = candidate; + } + } + } + } + } + return dpArr[0]; + } +} diff --git a/src/main/java/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/readme.md b/src/main/java/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/readme.md new file mode 100644 index 000000000..79101e859 --- /dev/null +++ b/src/main/java/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/readme.md @@ -0,0 +1,54 @@ +3563\. Lexicographically Smallest String After Adjacent Removals + +Hard + +You are given a string `s` consisting of lowercase English letters. + +You can perform the following operation any number of times (including zero): + +* Remove **any** 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 **lexicographically smallest** string that can be obtained after performing the operations optimally. + +**Note:** Consider the alphabet as circular, thus `'a'` and `'z'` are consecutive. + +**Example 1:** + +**Input:** s = "abc" + +**Output:** "a" + +**Explanation:** + +* Remove `"bc"` from the string, leaving `"a"` as the remaining string. +* No further operations are possible. Thus, the lexicographically smallest string after all possible removals is `"a"`. + +**Example 2:** + +**Input:** s = "bcda" + +**Output:** "" + +**Explanation:** + +* Remove `"cd"` from the string, leaving `"ba"` as the remaining string. +* Remove `"ba"` from the string, leaving `""` as the remaining string. +* No further operations are possible. Thus, the lexicographically smallest string after all possible removals is `""`. + +**Example 3:** + +**Input:** s = "zdce" + +**Output:** "zdce" + +**Explanation:** + +* Remove `"dc"` from the string, leaving `"ze"` as the remaining string. +* No further operations are possible on `"ze"`. +* However, since `"zdce"` is lexicographically smaller than `"ze"`, the smallest string after all possible removals is `"zdce"`. + +**Constraints:** + +* `1 <= s.length <= 250` +* `s` consists only of lowercase English letters. \ No newline at end of file diff --git a/src/test/java/g3501_3600/s3556_sum_of_largest_prime_substrings/SolutionTest.java b/src/test/java/g3501_3600/s3556_sum_of_largest_prime_substrings/SolutionTest.java new file mode 100644 index 000000000..a60a99bc0 --- /dev/null +++ b/src/test/java/g3501_3600/s3556_sum_of_largest_prime_substrings/SolutionTest.java @@ -0,0 +1,18 @@ +package g3501_3600.s3556_sum_of_largest_prime_substrings; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void sumOfLargestPrimes() { + assertThat(new Solution().sumOfLargestPrimes("12234"), equalTo(1469L)); + } + + @Test + void sumOfLargestPrimes2() { + assertThat(new Solution().sumOfLargestPrimes("111"), equalTo(11L)); + } +} diff --git a/src/test/java/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/SolutionTest.java b/src/test/java/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/SolutionTest.java new file mode 100644 index 000000000..13271a6f9 --- /dev/null +++ b/src/test/java/g3501_3600/s3557_find_maximum_number_of_non_intersecting_substrings/SolutionTest.java @@ -0,0 +1,18 @@ +package g3501_3600.s3557_find_maximum_number_of_non_intersecting_substrings; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void maxSubstrings() { + assertThat(new Solution().maxSubstrings("abcdeafdef"), equalTo(2)); + } + + @Test + void maxSubstrings2() { + assertThat(new Solution().maxSubstrings("bcdaaaab"), equalTo(1)); + } +} diff --git a/src/test/java/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/SolutionTest.java b/src/test/java/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/SolutionTest.java new file mode 100644 index 000000000..b4a7e49e0 --- /dev/null +++ b/src/test/java/g3501_3600/s3558_number_of_ways_to_assign_edge_weights_i/SolutionTest.java @@ -0,0 +1,20 @@ +package g3501_3600.s3558_number_of_ways_to_assign_edge_weights_i; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void assignEdgeWeights() { + assertThat(new Solution().assignEdgeWeights(new int[][] {{1, 2}}), equalTo(1)); + } + + @Test + void assignEdgeWeights2() { + assertThat( + new Solution().assignEdgeWeights(new int[][] {{1, 2}, {1, 3}, {3, 4}, {3, 5}}), + equalTo(2)); + } +} diff --git a/src/test/java/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/SolutionTest.java b/src/test/java/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/SolutionTest.java new file mode 100644 index 000000000..14b29eef3 --- /dev/null +++ b/src/test/java/g3501_3600/s3559_number_of_ways_to_assign_edge_weights_ii/SolutionTest.java @@ -0,0 +1,26 @@ +package g3501_3600.s3559_number_of_ways_to_assign_edge_weights_ii; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void assignEdgeWeights() { + assertThat( + new Solution() + .assignEdgeWeights(new int[][] {{1, 2}}, new int[][] {{1, 1}, {1, 2}}), + equalTo(new int[] {0, 1})); + } + + @Test + void assignEdgeWeights2() { + assertThat( + new Solution() + .assignEdgeWeights( + new int[][] {{1, 2}, {1, 3}, {3, 4}, {3, 5}}, + new int[][] {{1, 4}, {3, 4}, {2, 5}}), + equalTo(new int[] {2, 1, 4})); + } +} diff --git a/src/test/java/g3501_3600/s3560_find_minimum_log_transportation_cost/SolutionTest.java b/src/test/java/g3501_3600/s3560_find_minimum_log_transportation_cost/SolutionTest.java new file mode 100644 index 000000000..3c59f847c --- /dev/null +++ b/src/test/java/g3501_3600/s3560_find_minimum_log_transportation_cost/SolutionTest.java @@ -0,0 +1,75 @@ +package g3501_3600.s3560_find_minimum_log_transportation_cost; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void minCuttingCost() { + assertThat(new Solution().minCuttingCost(6, 5, 5), equalTo(5L)); + } + + @Test + void minCuttingCost2() { + assertThat(new Solution().minCuttingCost(4, 4, 6), equalTo(0L)); + } + + @Test + void minCuttingCost3() { + assertThat(new Solution().minCuttingCost(0, 5, 3), equalTo(0L)); + } + + @Test + void minCuttingCost4() { + assertThat(new Solution().minCuttingCost(5, 0, 3), equalTo(0L)); + } + + @Test + void minCuttingCost5() { + assertThat(new Solution().minCuttingCost(5, 3, 0), equalTo(0L)); + } + + @Test + void minCuttingCost6() { + assertThat(new Solution().minCuttingCost(2, 2, 2), equalTo(0L)); + } + + @Test + void minCuttingCost7() { + assertThat(new Solution().minCuttingCost(1, 1, 3), equalTo(0L)); + } + + @Test + void minCuttingCost8() { + assertThat(new Solution().minCuttingCost(2, 5, 2), equalTo(6L)); + } + + @Test + void minCuttingCost9() { + assertThat(new Solution().minCuttingCost(1, 10, 9), equalTo(9L)); + } + + @Test + void minCuttingCost10() { + assertThat(new Solution().minCuttingCost(8, 3, 2), equalTo(0L)); + } + + @Test + void minCuttingCost11() { + assertThat(new Solution().minCuttingCost(11, 5, 9), equalTo((11L - 9L) * 9L)); + } + + @Test + void minCuttingCost12() { + assertThat(new Solution().minCuttingCost(10, 15, 2), equalTo(0L)); + } + + @Test + void minCuttingCost13() { + assertThat( + new Solution().minCuttingCost(Integer.MAX_VALUE, Integer.MAX_VALUE, 2), + equalTo(0L)); + } +} diff --git a/src/test/java/g3501_3600/s3561_resulting_string_after_adjacent_removals/SolutionTest.java b/src/test/java/g3501_3600/s3561_resulting_string_after_adjacent_removals/SolutionTest.java new file mode 100644 index 000000000..d09818dfb --- /dev/null +++ b/src/test/java/g3501_3600/s3561_resulting_string_after_adjacent_removals/SolutionTest.java @@ -0,0 +1,23 @@ +package g3501_3600.s3561_resulting_string_after_adjacent_removals; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void resultingString() { + assertThat(new Solution().resultingString("abc"), equalTo("c")); + } + + @Test + void resultingString2() { + assertThat(new Solution().resultingString("adcb"), equalTo("")); + } + + @Test + void resultingString3() { + assertThat(new Solution().resultingString("zadb"), equalTo("db")); + } +} diff --git a/src/test/java/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/SolutionTest.java b/src/test/java/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/SolutionTest.java new file mode 100644 index 000000000..fdb0883da --- /dev/null +++ b/src/test/java/g3501_3600/s3562_maximum_profit_from_trading_stocks_with_discounts/SolutionTest.java @@ -0,0 +1,50 @@ +package g3501_3600.s3562_maximum_profit_from_trading_stocks_with_discounts; + +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[] {1, 2}, new int[] {4, 3}, new int[][] {{1, 2}}, 3), + equalTo(5)); + } + + @Test + void maxProfit2() { + assertThat( + new Solution() + .maxProfit(2, new int[] {3, 4}, new int[] {5, 8}, new int[][] {{1, 2}}, 4), + equalTo(4)); + } + + @Test + void maxProfit3() { + assertThat( + new Solution() + .maxProfit( + 3, + new int[] {4, 6, 8}, + new int[] {7, 9, 11}, + new int[][] {{1, 2}, {1, 3}}, + 10), + equalTo(10)); + } + + @Test + void maxProfit4() { + assertThat( + new Solution() + .maxProfit( + 3, + new int[] {5, 2, 3}, + new int[] {8, 5, 6}, + new int[][] {{1, 2}, {1, 3}}, + 7), + equalTo(12)); + } +} diff --git a/src/test/java/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/SolutionTest.java b/src/test/java/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/SolutionTest.java new file mode 100644 index 000000000..77f0e3da4 --- /dev/null +++ b/src/test/java/g3501_3600/s3563_lexicographically_smallest_string_after_adjacent_removals/SolutionTest.java @@ -0,0 +1,23 @@ +package g3501_3600.s3563_lexicographically_smallest_string_after_adjacent_removals; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void lexicographicallySmallestString() { + assertThat(new Solution().lexicographicallySmallestString("abc"), equalTo("a")); + } + + @Test + void lexicographicallySmallestString2() { + assertThat(new Solution().lexicographicallySmallestString("bcda"), equalTo("")); + } + + @Test + void lexicographicallySmallestString3() { + assertThat(new Solution().lexicographicallySmallestString("zdce"), equalTo("zdce")); + } +}