From cc21c81755db9a4f8da83561346db2372b9a5cf9 Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Sun, 30 Mar 2025 17:09:45 +0300 Subject: [PATCH 01/10] Added tasks 3498-3501 --- .../Solution.java | 13 ++ .../readme.md | 50 +++++++ .../Solution.java | 29 +++++ .../readme.md | 68 ++++++++++ .../Solution.java | 69 ++++++++++ .../readme.md | 47 +++++++ .../Solution.java | 122 ++++++++++++++++++ .../readme.md | 105 +++++++++++++++ .../SolutionTest.java | 18 +++ .../SolutionTest.java | 28 ++++ .../SolutionTest.java | 26 ++++ .../SolutionTest.java | 42 ++++++ 12 files changed, 617 insertions(+) create mode 100644 src/main/java/g3401_3500/s3498_reverse_degree_of_a_string/Solution.java create mode 100644 src/main/java/g3401_3500/s3498_reverse_degree_of_a_string/readme.md create mode 100644 src/main/java/g3401_3500/s3499_maximize_active_section_with_trade_i/Solution.java create mode 100644 src/main/java/g3401_3500/s3499_maximize_active_section_with_trade_i/readme.md create mode 100644 src/main/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/Solution.java create mode 100644 src/main/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/readme.md create mode 100644 src/main/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/Solution.java create mode 100644 src/main/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/readme.md create mode 100644 src/test/java/g3401_3500/s3498_reverse_degree_of_a_string/SolutionTest.java create mode 100644 src/test/java/g3401_3500/s3499_maximize_active_section_with_trade_i/SolutionTest.java create mode 100644 src/test/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/SolutionTest.java create mode 100644 src/test/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/SolutionTest.java diff --git a/src/main/java/g3401_3500/s3498_reverse_degree_of_a_string/Solution.java b/src/main/java/g3401_3500/s3498_reverse_degree_of_a_string/Solution.java new file mode 100644 index 000000000..09d93d987 --- /dev/null +++ b/src/main/java/g3401_3500/s3498_reverse_degree_of_a_string/Solution.java @@ -0,0 +1,13 @@ +package g3401_3500.s3498_reverse_degree_of_a_string; + +// #Easy #2025_03_30_Time_1_ms_(100.00%)_Space_43.05_MB_(100.00%) + +public class Solution { + public int reverseDegree(String s) { + int ans = 0; + for (int i = 0; i < s.length(); ++i) { + ans += (26 - (s.charAt(i) - 'a')) * (i + 1); + } + return ans; + } +} diff --git a/src/main/java/g3401_3500/s3498_reverse_degree_of_a_string/readme.md b/src/main/java/g3401_3500/s3498_reverse_degree_of_a_string/readme.md new file mode 100644 index 000000000..d8837fcd3 --- /dev/null +++ b/src/main/java/g3401_3500/s3498_reverse_degree_of_a_string/readme.md @@ -0,0 +1,50 @@ +3498\. Reverse Degree of a String + +Easy + +Given a string `s`, calculate its **reverse degree**. + +The **reverse degree** is calculated as follows: + +1. For each character, multiply its position in the _reversed_ alphabet (`'a'` = 26, `'b'` = 25, ..., `'z'` = 1) with its position in the string **(1-indexed)**. +2. Sum these products for all characters in the string. + +Return the **reverse degree** of `s`. + +**Example 1:** + +**Input:** s = "abc" + +**Output:** 148 + +**Explanation:** + +| Letter | Index in Reversed Alphabet | Index in String | Product | +|---------|----------------------------|----------------|---------| +| `'a'` | 26 | 1 | 26 | +| `'b'` | 25 | 2 | 50 | +| `'c'` | 24 | 3 | 72 | + +The reversed degree is `26 + 50 + 72 = 148`. + +**Example 2:** + +**Input:** s = "zaza" + +**Output:** 160 + +**Explanation:** + +| Letter | Index in Reversed Alphabet | Index in String | Product | +|---------|----------------------------|----------------|---------| +| `'z'` | 1 | 1 | 1 | +| `'a'` | 26 | 2 | 52 | +| `'z'` | 1 | 3 | 3 | +| `'a'` | 26 | 4 | 104 | + +The reverse degree is `1 + 52 + 3 + 104 = 160`. + +**Constraints:** + +* `1 <= s.length <= 1000` +* `s` contains only lowercase English letters. \ No newline at end of file diff --git a/src/main/java/g3401_3500/s3499_maximize_active_section_with_trade_i/Solution.java b/src/main/java/g3401_3500/s3499_maximize_active_section_with_trade_i/Solution.java new file mode 100644 index 000000000..181b8944d --- /dev/null +++ b/src/main/java/g3401_3500/s3499_maximize_active_section_with_trade_i/Solution.java @@ -0,0 +1,29 @@ +package g3401_3500.s3499_maximize_active_section_with_trade_i; + +// #Medium #2025_03_30_Time_55_ms_(100.00%)_Space_45.50_MB_(100.00%) + +public class Solution { + public int maxActiveSectionsAfterTrade(String s) { + int oneCount = 0; + int convertedOne = 0; + int curZeroCount = 0; + int lastZeroCount = 0; + for (int i = 0; i < s.length(); ++i) { + if (s.charAt(i) == '0') { + curZeroCount++; + } else { + if (curZeroCount != 0) { + lastZeroCount = curZeroCount; + } + curZeroCount = 0; + oneCount++; + } + convertedOne = Math.max(convertedOne, curZeroCount + lastZeroCount); + } + // corner case + if (convertedOne == curZeroCount || convertedOne == lastZeroCount) { + return oneCount; + } + return oneCount + convertedOne; + } +} diff --git a/src/main/java/g3401_3500/s3499_maximize_active_section_with_trade_i/readme.md b/src/main/java/g3401_3500/s3499_maximize_active_section_with_trade_i/readme.md new file mode 100644 index 000000000..2d6c49c5a --- /dev/null +++ b/src/main/java/g3401_3500/s3499_maximize_active_section_with_trade_i/readme.md @@ -0,0 +1,68 @@ +3499\. Maximize Active Section with Trade I + +Medium + +You are given a binary string `s` of length `n`, where: + +* `'1'` represents an **active** section. +* `'0'` represents an **inactive** section. + +You can perform **at most one trade** to maximize the number of active sections in `s`. In a trade, you: + +* Convert a contiguous block of `'1'`s that is surrounded by `'0'`s to all `'0'`s. +* Afterward, convert a contiguous block of `'0'`s that is surrounded by `'1'`s to all `'1'`s. + +Return the **maximum** number of active sections in `s` after making the optimal trade. + +**Note:** Treat `s` as if it is **augmented** with a `'1'` at both ends, forming `t = '1' + s + '1'`. The augmented `'1'`s **do not** contribute to the final count. + +**Example 1:** + +**Input:** s = "01" + +**Output:** 1 + +**Explanation:** + +Because there is no block of `'1'`s surrounded by `'0'`s, no valid trade is possible. The maximum number of active sections is 1. + +**Example 2:** + +**Input:** s = "0100" + +**Output:** 4 + +**Explanation:** + +* String `"0100"` → Augmented to `"101001"`. +* Choose `"0100"`, convert "10**1**001""1**0000**1""1**1111**1". +* The final string without augmentation is `"1111"`. The maximum number of active sections is 4. + +**Example 3:** + +**Input:** s = "1000100" + +**Output:** 7 + +**Explanation:** + +* String `"1000100"` → Augmented to `"110001001"`. +* Choose `"000100"`, convert "11000**1**001""11**000000**1""11**111111**1". +* The final string without augmentation is `"1111111"`. The maximum number of active sections is 7. + +**Example 4:** + +**Input:** s = "01010" + +**Output:** 4 + +**Explanation:** + +* String `"01010"` → Augmented to `"1010101"`. +* Choose `"010"`, convert "10**1**0101""1**000**101""1**111**101". +* The final string without augmentation is `"11110"`. The maximum number of active sections is 4. + +**Constraints:** + +* 1 <= n == s.length <= 105 +* `s[i]` is either `'0'` or `'1'` \ No newline at end of file diff --git a/src/main/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/Solution.java b/src/main/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/Solution.java new file mode 100644 index 000000000..78d51b809 --- /dev/null +++ b/src/main/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/Solution.java @@ -0,0 +1,69 @@ +package g3401_3500.s3500_minimum_cost_to_divide_array_into_subarrays; + +// #Hard #2025_03_30_Time_225_ms_(94.64%)_Space_62.54_MB_(58.93%) + +import java.util.Arrays; + +public class Solution { + public long minimumCost(int[] nums, int[] cost, int k) { + int n = nums.length; + long[] prefixNums = new long[n]; + long total = 0; + for (int i = 0; i < n; i++) { + total += nums[i]; + prefixNums[i] = total; + } + long[] prefixCost = new long[n + 1]; + total = 0; + for (int i = 0; i < n; i++) { + total += cost[i]; + prefixCost[i + 1] = total; + } + long[][] memo = new long[n][n + 1]; + for (long[] row : memo) { + Arrays.fill(row, -1); + } + int[] bestSplit = new int[n]; + Arrays.fill(bestSplit, -1); + return rec(0, 1, nums, prefixNums, prefixCost, k, memo, bestSplit); + } + + private long rec( + int index, + int i, + int[] nums, + long[] prefixNums, + long[] prefixCost, + int k, + long[][] memo, + int[] bestSplit) { + int n = nums.length; + if (index == n) { + return 0; + } + if (memo[index][i] != -1) { + return memo[index][i]; + } + if (bestSplit[index] != -1) { + int j = bestSplit[index]; + long val = + (prefixNums[j] + (long) k * i) * (prefixCost[j + 1] - prefixCost[index]) + + rec(j + 1, i + 1, nums, prefixNums, prefixCost, k, memo, bestSplit); + return memo[index][i] = val; + } + long best = Long.MAX_VALUE; + int bestIndex = -1; + for (int j = index; j < n; j++) { + long val = + (prefixNums[j] + (long) k * i) * (prefixCost[j + 1] - prefixCost[index]) + + rec(j + 1, i + 1, nums, prefixNums, prefixCost, k, memo, bestSplit); + if (val < best) { + best = val; + bestIndex = j; + } + } + bestSplit[index] = bestIndex; + memo[index][i] = best; + return best; + } +} diff --git a/src/main/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/readme.md b/src/main/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/readme.md new file mode 100644 index 000000000..0c94b088f --- /dev/null +++ b/src/main/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/readme.md @@ -0,0 +1,47 @@ +3500\. Minimum Cost to Divide Array Into Subarrays + +Hard + +You are given two integer arrays, `nums` and `cost`, of the same size, and an integer `k`. + +You can divide `nums` into **non-empty subarrays**. The cost of the ith subarray consisting of elements `nums[l..r]` is: + +* `(nums[0] + nums[1] + ... + nums[r] + k * i) * (cost[l] + cost[l + 1] + ... + cost[r])`. + +**Note** that `i` represents the order of the subarray: 1 for the first subarray, 2 for the second, and so on. + +Return the **minimum** total cost possible from any valid division. + +**Example 1:** + +**Input:** nums = [3,1,4], cost = [4,6,6], k = 1 + +**Output:** 110 + +**Explanation:** + +The minimum total cost possible can be achieved by dividing `nums` into subarrays `[3, 1]` and `[4]`. + +* The cost of the first subarray `[3,1]` is `(3 + 1 + 1 * 1) * (4 + 6) = 50`. +* The cost of the second subarray `[4]` is `(3 + 1 + 4 + 1 * 2) * 6 = 60`. + +**Example 2:** + +**Input:** nums = [4,8,5,1,14,2,2,12,1], cost = [7,2,8,4,2,2,1,1,2], k = 7 + +**Output:** 985 + +**Explanation:** + +The minimum total cost possible can be achieved by dividing `nums` into subarrays `[4, 8, 5, 1]`, `[14, 2, 2]`, and `[12, 1]`. + +* The cost of the first subarray `[4, 8, 5, 1]` is `(4 + 8 + 5 + 1 + 7 * 1) * (7 + 2 + 8 + 4) = 525`. +* The cost of the second subarray `[14, 2, 2]` is `(4 + 8 + 5 + 1 + 14 + 2 + 2 + 7 * 2) * (2 + 2 + 1) = 250`. +* The cost of the third subarray `[12, 1]` is `(4 + 8 + 5 + 1 + 14 + 2 + 2 + 12 + 1 + 7 * 3) * (1 + 2) = 210`. + +**Constraints:** + +* `1 <= nums.length <= 1000` +* `cost.length == nums.length` +* `1 <= nums[i], cost[i] <= 1000` +* `1 <= k <= 1000` \ No newline at end of file diff --git a/src/main/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/Solution.java b/src/main/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/Solution.java new file mode 100644 index 000000000..0157547ea --- /dev/null +++ b/src/main/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/Solution.java @@ -0,0 +1,122 @@ +package g3501_3600.s3501_maximize_active_section_with_trade_ii; + +// #Hard #2025_03_30_Time_260_ms_(100.00%)_Space_119.42_MB_(100.00%) + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class Solution { + private static final int INF = (int) 1e9; + private static final int NEG_INF = -INF; + + public List maxActiveSectionsAfterTrade(String s, int[][] queries) { + int n = s.length(); + int activeCount = 0; + for (char ch : s.toCharArray()) { + if (ch == '1') { + activeCount++; + } + } + List segments = new ArrayList<>(); + for (int i = 0, start = 0; i < n; i++) { + if (i == n - 1 || s.charAt(i) != s.charAt(i + 1)) { + segments.add(new int[] {start, i - start + 1}); + start = i + 1; + } + } + int segmentCount = segments.size(); + int maxPower = 20; + int[][] rmq = new int[maxPower][segmentCount]; + for (int i = 0; i < maxPower; i++) { + Arrays.fill(rmq[i], NEG_INF); + } + for (int i = 0; i < segmentCount; i++) { + if (s.charAt(segments.get(i)[0]) == '0' && i + 2 < segmentCount) { + rmq[0][i] = segments.get(i)[1] + segments.get(i + 2)[1]; + } + } + for (int power = 1, rangeLen = 2; power < maxPower; power++, rangeLen *= 2) { + for (int i = 0, j = rangeLen - 1; j < segmentCount; i++, j++) { + rmq[power][i] = Math.max(rmq[power - 1][i], rmq[power - 1][i + rangeLen / 2]); + } + } + List result = new ArrayList<>(); + for (int[] query : queries) { + int left = query[0], right = query[1]; + int leftIndex = binarySearch(segments, left) - 1; + int rightIndex = binarySearch(segments, right) - 1; + if (rightIndex - leftIndex + 1 <= 2) { + result.add(activeCount); + continue; + } + int bestIncrease = Math.max(getMaxInRange(rmq, leftIndex + 1, rightIndex - 3), 0); + bestIncrease = + Math.max( + bestIncrease, + calculateNewSections( + s, segments, left, right, leftIndex, rightIndex, leftIndex)); + bestIncrease = + Math.max( + bestIncrease, + calculateNewSections( + s, + segments, + left, + right, + leftIndex, + rightIndex, + rightIndex - 2)); + result.add(activeCount + bestIncrease); + } + return result; + } + + private int binarySearch(List segments, int key) { + int lo = 0, hi = segments.size(); + while (lo < hi) { + int mid = lo + (hi - lo) / 2; + if (segments.get(mid)[0] > key) { + hi = mid; + } else { + lo = mid + 1; + } + } + return lo; + } + + private int getMaxInRange(int[][] rmq, int left, int right) { + if (left > right) { + return NEG_INF; + } + int power = 31 - Integer.numberOfLeadingZeros(right - left + 1); + return Math.max(rmq[power][left], rmq[power][right - (1 << power) + 1]); + } + + private int getSegmentSize( + List segments, int left, int right, int leftIndex, int rightIndex, int i) { + if (i == leftIndex) { + return segments.get(leftIndex)[1] - (left - segments.get(leftIndex)[0]); + } + if (i == rightIndex) { + return right - segments.get(rightIndex)[0] + 1; + } + return segments.get(i)[1]; + } + + private int calculateNewSections( + String s, + List segments, + int left, + int right, + int leftIndex, + int rightIndex, + int i) { + if (i < 0 || i + 2 >= segments.size() || s.charAt(segments.get(i)[0]) == '1') { + return NEG_INF; + } + int size1 = getSegmentSize(segments, left, right, leftIndex, rightIndex, i); + int size2 = getSegmentSize(segments, left, right, leftIndex, rightIndex, i + 2); + return size1 + size2; + } +} diff --git a/src/main/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/readme.md b/src/main/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/readme.md new file mode 100644 index 000000000..740d75a33 --- /dev/null +++ b/src/main/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/readme.md @@ -0,0 +1,105 @@ +3501\. Maximize Active Section with Trade II + +Hard + +You are given a binary string `s` of length `n`, where: + +* `'1'` represents an **active** section. +* `'0'` represents an **inactive** section. + +You can perform **at most one trade** to maximize the number of active sections in `s`. In a trade, you: + +* Convert a contiguous block of `'1'`s that is surrounded by `'0'`s to all `'0'`s. +* Afterward, convert a contiguous block of `'0'`s that is surrounded by `'1'`s to all `'1'`s. + +Additionally, you are given a **2D array** `queries`, where queries[i] = [li, ri] represents a **substring** s[li...ri]. + +For each query, determine the **maximum** possible number of active sections in `s` after making the optimal trade on the substring s[li...ri]. + +Return an array `answer`, where `answer[i]` is the result for `queries[i]`. + +**Note** + +* For each query, treat s[li...ri] as if it is **augmented** with a `'1'` at both ends, forming t = '1' + s[li...ri] + '1'. The augmented `'1'`s **do not** contribute to the final count. +* The queries are independent of each other. + +**Example 1:** + +**Input:** s = "01", queries = [[0,1]] + +**Output:** [1] + +**Explanation:** + +Because there is no block of `'1'`s surrounded by `'0'`s, no valid trade is possible. The maximum number of active sections is 1. + +**Example 2:** + +**Input:** s = "0100", queries = [[0,3],[0,2],[1,3],[2,3]] + +**Output:** [4,3,1,1] + +**Explanation:** + +* Query `[0, 3]` → Substring `"0100"` → Augmented to `"101001"` + Choose `"0100"`, convert `"0100"` → `"0000"` → `"1111"`. + The final string without augmentation is `"1111"`. The maximum number of active sections is 4. + +* Query `[0, 2]` → Substring `"010"` → Augmented to `"10101"` + Choose `"010"`, convert `"010"` → `"000"` → `"111"`. + The final string without augmentation is `"1110"`. The maximum number of active sections is 3. + +* Query `[1, 3]` → Substring `"100"` → Augmented to `"11001"` + Because there is no block of `'1'`s surrounded by `'0'`s, no valid trade is possible. The maximum number of active sections is 1. + +* Query `[2, 3]` → Substring `"00"` → Augmented to `"1001"` + Because there is no block of `'1'`s surrounded by `'0'`s, no valid trade is possible. The maximum number of active sections is 1. + + +**Example 3:** + +**Input:** s = "1000100", queries = [[1,5],[0,6],[0,4]] + +**Output:** [6,7,2] + +**Explanation:** + +* Query `[1, 5]` → Substring `"00010"` → Augmented to `"1000101"` + Choose `"00010"`, convert `"00010"` → `"00000"` → `"11111"`. + The final string without augmentation is `"1111110"`. The maximum number of active sections is 6. + +* Query `[0, 6]` → Substring `"1000100"` → Augmented to `"110001001"` + Choose `"000100"`, convert `"000100"` → `"000000"` → `"111111"`. + The final string without augmentation is `"1111111"`. The maximum number of active sections is 7. + +* Query `[0, 4]` → Substring `"10001"` → Augmented to `"1100011"` + Because there is no block of `'1'`s surrounded by `'0'`s, no valid trade is possible. The maximum number of active sections is 2. + + +**Example 4:** + +**Input:** s = "01010", queries = [[0,3],[1,4],[1,3]] + +**Output:** [4,4,2] + +**Explanation:** + +* Query `[0, 3]` → Substring `"0101"` → Augmented to `"101011"` + Choose `"010"`, convert `"010"` → `"000"` → `"111"`. + The final string without augmentation is `"11110"`. The maximum number of active sections is 4. + +* Query `[1, 4]` → Substring `"1010"` → Augmented to `"110101"` + Choose `"010"`, convert `"010"` → `"000"` → `"111"`. + The final string without augmentation is `"01111"`. The maximum number of active sections is 4. + +* Query `[1, 3]` → Substring `"101"` → Augmented to `"11011"` + Because there is no block of `'1'`s surrounded by `'0'`s, no valid trade is possible. The maximum number of active sections is 2. + + +**Constraints:** + +* 1 <= n == s.length <= 105 +* 1 <= queries.length <= 105 +* `s[i]` is either `'0'` or `'1'`. +* queries[i] = [li, ri] +* 0 <= li <= ri < n \ No newline at end of file diff --git a/src/test/java/g3401_3500/s3498_reverse_degree_of_a_string/SolutionTest.java b/src/test/java/g3401_3500/s3498_reverse_degree_of_a_string/SolutionTest.java new file mode 100644 index 000000000..82a81094a --- /dev/null +++ b/src/test/java/g3401_3500/s3498_reverse_degree_of_a_string/SolutionTest.java @@ -0,0 +1,18 @@ +package g3401_3500.s3498_reverse_degree_of_a_string; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void reverseDegree() { + assertThat(new Solution().reverseDegree("abc"), equalTo(148)); + } + + @Test + void reverseDegree2() { + assertThat(new Solution().reverseDegree("zaza"), equalTo(160)); + } +} diff --git a/src/test/java/g3401_3500/s3499_maximize_active_section_with_trade_i/SolutionTest.java b/src/test/java/g3401_3500/s3499_maximize_active_section_with_trade_i/SolutionTest.java new file mode 100644 index 000000000..eb30b637f --- /dev/null +++ b/src/test/java/g3401_3500/s3499_maximize_active_section_with_trade_i/SolutionTest.java @@ -0,0 +1,28 @@ +package g3401_3500.s3499_maximize_active_section_with_trade_i; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void maxActiveSectionsAfterTrade() { + assertThat(new Solution().maxActiveSectionsAfterTrade("01"), equalTo(1)); + } + + @Test + void maxActiveSectionsAfterTrade2() { + assertThat(new Solution().maxActiveSectionsAfterTrade("0100"), equalTo(4)); + } + + @Test + void maxActiveSectionsAfterTrade3() { + assertThat(new Solution().maxActiveSectionsAfterTrade("1000100"), equalTo(7)); + } + + @Test + void maxActiveSectionsAfterTrade4() { + assertThat(new Solution().maxActiveSectionsAfterTrade("01010"), equalTo(4)); + } +} diff --git a/src/test/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/SolutionTest.java b/src/test/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/SolutionTest.java new file mode 100644 index 000000000..e32f9c9e2 --- /dev/null +++ b/src/test/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/SolutionTest.java @@ -0,0 +1,26 @@ +package g3401_3500.s3500_minimum_cost_to_divide_array_into_subarrays; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void minimumCost() { + assertThat( + new Solution().minimumCost(new int[] {3, 1, 4}, new int[] {4, 6, 6}, 1), + equalTo(110L)); + } + + @Test + void minimumCost2() { + assertThat( + new Solution() + .minimumCost( + new int[] {4, 8, 5, 1, 14, 2, 2, 12, 1}, + new int[] {7, 2, 8, 4, 2, 2, 1, 1, 2}, + 7), + equalTo(985L)); + } +} diff --git a/src/test/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/SolutionTest.java b/src/test/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/SolutionTest.java new file mode 100644 index 000000000..a8464f907 --- /dev/null +++ b/src/test/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/SolutionTest.java @@ -0,0 +1,42 @@ +package g3501_3600.s3501_maximize_active_section_with_trade_ii; + +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 maxActiveSectionsAfterTrade() { + assertThat( + new Solution().maxActiveSectionsAfterTrade("01", new int[][] {{0, 1}}), + equalTo(List.of(1))); + } + + @Test + void maxActiveSectionsAfterTrade2() { + assertThat( + new Solution() + .maxActiveSectionsAfterTrade( + "0100", new int[][] {{0, 3}, {0, 2}, {1, 3}, {2, 3}}), + equalTo(List.of(4, 3, 1, 1))); + } + + @Test + void maxActiveSectionsAfterTrade3() { + assertThat( + new Solution() + .maxActiveSectionsAfterTrade( + "1000100", new int[][] {{1, 5}, {0, 6}, {0, 4}}), + equalTo(List.of(6, 7, 2))); + } + + @Test + void maxActiveSectionsAfterTrade4() { + assertThat( + new Solution() + .maxActiveSectionsAfterTrade("01010", new int[][] {{0, 3}, {1, 4}, {1, 3}}), + equalTo(List.of(4, 4, 2))); + } +} From 152997d6c81c41127561ec25a3473b379ba935ae Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Sun, 30 Mar 2025 17:12:20 +0300 Subject: [PATCH 02/10] Fixed format --- .../Solution.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/Solution.java b/src/main/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/Solution.java index 0157547ea..ceec01ce5 100644 --- a/src/main/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/Solution.java +++ b/src/main/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/Solution.java @@ -43,7 +43,8 @@ public List maxActiveSectionsAfterTrade(String s, int[][] queries) { } List result = new ArrayList<>(); for (int[] query : queries) { - int left = query[0], right = query[1]; + int left = query[0]; + int right = query[1]; int leftIndex = binarySearch(segments, left) - 1; int rightIndex = binarySearch(segments, right) - 1; if (rightIndex - leftIndex + 1 <= 2) { @@ -73,7 +74,8 @@ public List maxActiveSectionsAfterTrade(String s, int[][] queries) { } private int binarySearch(List segments, int key) { - int lo = 0, hi = segments.size(); + int lo = 0; + int hi = segments.size(); while (lo < hi) { int mid = lo + (hi - lo) / 2; if (segments.get(mid)[0] > key) { From a71e493c0488a37a4c0952089521e03841cd6b2f Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Sun, 30 Mar 2025 17:24:13 +0300 Subject: [PATCH 03/10] Fixed sonar --- .../Solution.java | 4 +++- .../s3501_maximize_active_section_with_trade_ii/Solution.java | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/Solution.java b/src/main/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/Solution.java index 78d51b809..d7af0b5d8 100644 --- a/src/main/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/Solution.java +++ b/src/main/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/Solution.java @@ -4,6 +4,7 @@ import java.util.Arrays; +@SuppressWarnings("java:S107") public class Solution { public long minimumCost(int[] nums, int[] cost, int k) { int n = nums.length; @@ -49,7 +50,8 @@ private long rec( long val = (prefixNums[j] + (long) k * i) * (prefixCost[j + 1] - prefixCost[index]) + rec(j + 1, i + 1, nums, prefixNums, prefixCost, k, memo, bestSplit); - return memo[index][i] = val; + memo[index][i] = val; + return val; } long best = Long.MAX_VALUE; int bestIndex = -1; diff --git a/src/main/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/Solution.java b/src/main/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/Solution.java index ceec01ce5..dab254a8c 100644 --- a/src/main/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/Solution.java +++ b/src/main/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/Solution.java @@ -19,7 +19,8 @@ public List maxActiveSectionsAfterTrade(String s, int[][] queries) { } } List segments = new ArrayList<>(); - for (int i = 0, start = 0; i < n; i++) { + int start = 0; + for (int i = 0; i < n; i++) { if (i == n - 1 || s.charAt(i) != s.charAt(i + 1)) { segments.add(new int[] {start, i - start + 1}); start = i + 1; From c2a1554f1792d2bbbd976e3d08eee38de6a208ab Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Sun, 30 Mar 2025 17:39:05 +0300 Subject: [PATCH 04/10] Added test --- .../SolutionTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/test/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/SolutionTest.java b/src/test/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/SolutionTest.java index a8464f907..85c253c5b 100644 --- a/src/test/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/SolutionTest.java +++ b/src/test/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/SolutionTest.java @@ -39,4 +39,13 @@ void maxActiveSectionsAfterTrade4() { .maxActiveSectionsAfterTrade("01010", new int[][] {{0, 3}, {1, 4}, {1, 3}}), equalTo(List.of(4, 4, 2))); } + + @Test + void maxActiveSectionsAfterTrade5() { + assertThat( + new Solution() + .maxActiveSectionsAfterTrade( + "10110111", new int[][] {{3, 7}, {4, 6}, {0, 6}}), + equalTo(List.of(6, 6, 8))); + } } From c1bc7aacb328a7570d455cff8800b1a8c49bf4f8 Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Sun, 30 Mar 2025 18:42:09 +0300 Subject: [PATCH 05/10] Added tasks 3502-3505 --- .../Solution.java | 16 +++ .../readme.md | 46 ++++++ .../Solution.java | 37 +++++ .../readme.md | 54 +++++++ .../Solution.java | 82 +++++++++++ .../readme.md | 54 +++++++ .../Solution.java | 136 ++++++++++++++++++ .../readme.md | 40 ++++++ .../SolutionTest.java | 22 +++ .../SolutionTest.java | 28 ++++ .../SolutionTest.java | 28 ++++ .../SolutionTest.java | 21 +++ 12 files changed, 564 insertions(+) create mode 100644 src/main/java/g3501_3600/s3502_minimum_cost_to_reach_every_position/Solution.java create mode 100644 src/main/java/g3501_3600/s3502_minimum_cost_to_reach_every_position/readme.md create mode 100644 src/main/java/g3501_3600/s3503_longest_palindrome_after_substring_concatenation_i/Solution.java create mode 100644 src/main/java/g3501_3600/s3503_longest_palindrome_after_substring_concatenation_i/readme.md create mode 100644 src/main/java/g3501_3600/s3504_longest_palindrome_after_substring_concatenation_ii/Solution.java create mode 100644 src/main/java/g3501_3600/s3504_longest_palindrome_after_substring_concatenation_ii/readme.md create mode 100644 src/main/java/g3501_3600/s3505_minimum_operations_to_make_elements_within_k_subarrays_equal/Solution.java create mode 100644 src/main/java/g3501_3600/s3505_minimum_operations_to_make_elements_within_k_subarrays_equal/readme.md create mode 100644 src/test/java/g3501_3600/s3502_minimum_cost_to_reach_every_position/SolutionTest.java create mode 100644 src/test/java/g3501_3600/s3503_longest_palindrome_after_substring_concatenation_i/SolutionTest.java create mode 100644 src/test/java/g3501_3600/s3504_longest_palindrome_after_substring_concatenation_ii/SolutionTest.java create mode 100644 src/test/java/g3501_3600/s3505_minimum_operations_to_make_elements_within_k_subarrays_equal/SolutionTest.java diff --git a/src/main/java/g3501_3600/s3502_minimum_cost_to_reach_every_position/Solution.java b/src/main/java/g3501_3600/s3502_minimum_cost_to_reach_every_position/Solution.java new file mode 100644 index 000000000..c60d0bb24 --- /dev/null +++ b/src/main/java/g3501_3600/s3502_minimum_cost_to_reach_every_position/Solution.java @@ -0,0 +1,16 @@ +package g3501_3600.s3502_minimum_cost_to_reach_every_position; + +// #Easy #2025_03_30_Time_1_ms_(97.67%)_Space_44.71_MB_(95.61%) + +public class Solution { + public int[] minCosts(int[] cost) { + int min = cost[0]; + int[] ans = new int[cost.length]; + ans[0] = min; + for (int i = 1; i < cost.length; i++) { + min = Math.min(min, cost[i]); + ans[i] = min; + } + return ans; + } +} diff --git a/src/main/java/g3501_3600/s3502_minimum_cost_to_reach_every_position/readme.md b/src/main/java/g3501_3600/s3502_minimum_cost_to_reach_every_position/readme.md new file mode 100644 index 000000000..f3e580876 --- /dev/null +++ b/src/main/java/g3501_3600/s3502_minimum_cost_to_reach_every_position/readme.md @@ -0,0 +1,46 @@ +3502\. Minimum Cost to Reach Every Position + +Easy + +You are given an integer array `cost` of size `n`. You are currently at position `n` (at the end of the line) in a line of `n + 1` people (numbered from 0 to `n`). + +You wish to move forward in the line, but each person in front of you charges a specific amount to **swap** places. The cost to swap with person `i` is given by `cost[i]`. + +You are allowed to swap places with people as follows: + +* If they are in front of you, you **must** pay them `cost[i]` to swap with them. +* If they are behind you, they can swap with you for free. + +Return an array `answer` of size `n`, where `answer[i]` is the **minimum** total cost to reach each position `i` in the line. + +**Example 1:** + +**Input:** cost = [5,3,4,1,3,2] + +**Output:** [5,3,3,1,1,1] + +**Explanation:** + +We can get to each position in the following way: + +* `i = 0`. We can swap with person 0 for a cost of 5. +* `i = 1`. We can swap with person 1 for a cost of 3. +* `i = 2`. We can swap with person 1 for a cost of 3, then swap with person 2 for free. +* `i = 3`. We can swap with person 3 for a cost of 1. +* `i = 4`. We can swap with person 3 for a cost of 1, then swap with person 4 for free. +* `i = 5`. We can swap with person 3 for a cost of 1, then swap with person 5 for free. + +**Example 2:** + +**Input:** cost = [1,2,4,6,7] + +**Output:** [1,1,1,1,1] + +**Explanation:** + +We can swap with person 0 for a cost of 1, then we will be able to reach any position `i` for free. + +**Constraints:** + +* `1 <= n == cost.length <= 100` +* `1 <= cost[i] <= 100` \ No newline at end of file diff --git a/src/main/java/g3501_3600/s3503_longest_palindrome_after_substring_concatenation_i/Solution.java b/src/main/java/g3501_3600/s3503_longest_palindrome_after_substring_concatenation_i/Solution.java new file mode 100644 index 000000000..72d6e4c62 --- /dev/null +++ b/src/main/java/g3501_3600/s3503_longest_palindrome_after_substring_concatenation_i/Solution.java @@ -0,0 +1,37 @@ +package g3501_3600.s3503_longest_palindrome_after_substring_concatenation_i; + +// #Medium #2025_03_30_Time_389_ms_(56.95%)_Space_45.18_MB_(96.47%) + +public class Solution { + public int longestPalindrome(String s, String t) { + int result = 0; + for (int i = 0; i <= s.length(); i++) { + for (int j = i; j <= s.length(); j++) { + String subStrS = s.substring(i, j); + for (int k = 0; k <= t.length(); k++) { + for (int l = k; l <= t.length(); l++) { + String subStrT = t.substring(k, l); + String combineStr = subStrS + subStrT; + if (isPalindrome(combineStr)) { + result = Math.max(result, combineStr.length()); + } + } + } + } + } + return result; + } + + private boolean isPalindrome(String input) { + int left = 0; + int right = input.length() - 1; + while (left < right) { + if (input.charAt(left) != input.charAt(right)) { + return false; + } + left++; + right--; + } + return true; + } +} diff --git a/src/main/java/g3501_3600/s3503_longest_palindrome_after_substring_concatenation_i/readme.md b/src/main/java/g3501_3600/s3503_longest_palindrome_after_substring_concatenation_i/readme.md new file mode 100644 index 000000000..e340325e0 --- /dev/null +++ b/src/main/java/g3501_3600/s3503_longest_palindrome_after_substring_concatenation_i/readme.md @@ -0,0 +1,54 @@ +3503\. Longest Palindrome After Substring Concatenation I + +Medium + +You are given two strings, `s` and `t`. + +You can create a new string by selecting a **substring** from `s` (possibly empty) and a substring from `t` (possibly empty), then concatenating them **in order**. + +Return the length of the **longest** palindrome that can be formed this way. + +**Example 1:** + +**Input:** s = "a", t = "a" + +**Output:** 2 + +**Explanation:** + +Concatenating `"a"` from `s` and `"a"` from `t` results in `"aa"`, which is a palindrome of length 2. + +**Example 2:** + +**Input:** s = "abc", t = "def" + +**Output:** 1 + +**Explanation:** + +Since all characters are different, the longest palindrome is any single character, so the answer is 1. + +**Example 3:** + +**Input:** s = "b", t = "aaaa" + +**Output:** 4 + +**Explanation:** + +Selecting "`aaaa`" from `t` is the longest palindrome, so the answer is 4. + +**Example 4:** + +**Input:** s = "abcde", t = "ecdba" + +**Output:** 5 + +**Explanation:** + +Concatenating `"abc"` from `s` and `"ba"` from `t` results in `"abcba"`, which is a palindrome of length 5. + +**Constraints:** + +* `1 <= s.length, t.length <= 30` +* `s` and `t` consist of lowercase English letters. \ No newline at end of file diff --git a/src/main/java/g3501_3600/s3504_longest_palindrome_after_substring_concatenation_ii/Solution.java b/src/main/java/g3501_3600/s3504_longest_palindrome_after_substring_concatenation_ii/Solution.java new file mode 100644 index 000000000..7893f5458 --- /dev/null +++ b/src/main/java/g3501_3600/s3504_longest_palindrome_after_substring_concatenation_ii/Solution.java @@ -0,0 +1,82 @@ +package g3501_3600.s3504_longest_palindrome_after_substring_concatenation_ii; + +// #Hard #2025_03_30_Time_21_ms_(100.00%)_Space_56.36_MB_(57.78%) + +public class Solution { + private int[] sPa; + private int[] tPa; + private char[] ss; + private char[] tt; + + public int longestPalindrome(String s, String t) { + final int sLen = s.length(); + final int tLen = t.length(); + ss = s.toCharArray(); + tt = t.toCharArray(); + int[][] palindrome = new int[sLen][tLen + 1]; + sPa = new int[sLen]; + tPa = new int[tLen]; + int maxLen = 1; + for (int j = 0; j < tLen; j++) { + if (ss[0] == tt[j]) { + palindrome[0][j] = 2; + sPa[0] = 2; + tPa[j] = 2; + maxLen = 2; + } + } + for (int i = 1; i < sLen; i++) { + for (int j = 0; j < tLen; j++) { + if (ss[i] == tt[j]) { + palindrome[i][j] = 2 + palindrome[i - 1][j + 1]; + sPa[i] = Math.max(sPa[i], palindrome[i][j]); + tPa[j] = Math.max(tPa[j], palindrome[i][j]); + maxLen = Math.max(maxLen, palindrome[i][j]); + } + } + } + for (int i = 0; i < sLen - 1; i++) { + int len = maxS(i, i + 1); + maxLen = Math.max(maxLen, len); + } + for (int i = 1; i < sLen; i++) { + int len = maxS(i - 1, i + 1) + 1; + maxLen = Math.max(maxLen, len); + } + for (int j = 0; j < tLen - 1; j++) { + int len = maxT(j, j + 1); + maxLen = Math.max(maxLen, len); + } + for (int j = 0; j < tLen - 1; j++) { + int len = maxT(j - 1, j + 1) + 1; + maxLen = Math.max(maxLen, len); + } + return maxLen; + } + + private int maxS(int left, int right) { + int len = 0; + while (left >= 0 && right < ss.length && ss[left] == ss[right]) { + len += 2; + left--; + right++; + } + if (left >= 0) { + len += sPa[left]; + } + return len; + } + + private int maxT(int left, int right) { + int len = 0; + while (left >= 0 && right < tt.length && tt[left] == tt[right]) { + len += 2; + left--; + right++; + } + if (right < tt.length) { + len += tPa[right]; + } + return len; + } +} diff --git a/src/main/java/g3501_3600/s3504_longest_palindrome_after_substring_concatenation_ii/readme.md b/src/main/java/g3501_3600/s3504_longest_palindrome_after_substring_concatenation_ii/readme.md new file mode 100644 index 000000000..8760ac849 --- /dev/null +++ b/src/main/java/g3501_3600/s3504_longest_palindrome_after_substring_concatenation_ii/readme.md @@ -0,0 +1,54 @@ +3504\. Longest Palindrome After Substring Concatenation II + +Hard + +You are given two strings, `s` and `t`. + +You can create a new string by selecting a **substring** from `s` (possibly empty) and a substring from `t` (possibly empty), then concatenating them **in order**. + +Return the length of the **longest** palindrome that can be formed this way. + +**Example 1:** + +**Input:** s = "a", t = "a" + +**Output:** 2 + +**Explanation:** + +Concatenating `"a"` from `s` and `"a"` from `t` results in `"aa"`, which is a palindrome of length 2. + +**Example 2:** + +**Input:** s = "abc", t = "def" + +**Output:** 1 + +**Explanation:** + +Since all characters are different, the longest palindrome is any single character, so the answer is 1. + +**Example 3:** + +**Input:** s = "b", t = "aaaa" + +**Output:** 4 + +**Explanation:** + +Selecting "`aaaa`" from `t` is the longest palindrome, so the answer is 4. + +**Example 4:** + +**Input:** s = "abcde", t = "ecdba" + +**Output:** 5 + +**Explanation:** + +Concatenating `"abc"` from `s` and `"ba"` from `t` results in `"abcba"`, which is a palindrome of length 5. + +**Constraints:** + +* `1 <= s.length, t.length <= 1000` +* `s` and `t` consist of lowercase English letters. \ No newline at end of file diff --git a/src/main/java/g3501_3600/s3505_minimum_operations_to_make_elements_within_k_subarrays_equal/Solution.java b/src/main/java/g3501_3600/s3505_minimum_operations_to_make_elements_within_k_subarrays_equal/Solution.java new file mode 100644 index 000000000..3346d81c8 --- /dev/null +++ b/src/main/java/g3501_3600/s3505_minimum_operations_to_make_elements_within_k_subarrays_equal/Solution.java @@ -0,0 +1,136 @@ +package g3501_3600.s3505_minimum_operations_to_make_elements_within_k_subarrays_equal; + +// #Hard #2025_03_30_Time_512_ms_(95.52%)_Space_82.02_MB_(14.18%) + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.PriorityQueue; + +public class Solution { + private static class SlidingMedian { + // max-heap for smaller half + PriorityQueue leftHeap; + // min-heap for larger half + PriorityQueue rightHeap; + Map delayedRemovals; + long sumLeft; + long sumRight; + int sizeLeft; + int sizeRight; + + public SlidingMedian() { + leftHeap = new PriorityQueue<>(Collections.reverseOrder()); + rightHeap = new PriorityQueue<>(); + delayedRemovals = new HashMap<>(); + sumLeft = sumRight = 0; + sizeLeft = sizeRight = 0; + } + + public void add(int num) { + if (leftHeap.isEmpty() || num <= leftHeap.peek()) { + leftHeap.offer(num); + sumLeft += num; + sizeLeft++; + } else { + rightHeap.offer(num); + sumRight += num; + sizeRight++; + } + balanceHeaps(); + } + + public void remove(int num) { + delayedRemovals.put(num, delayedRemovals.getOrDefault(num, 0) + 1); + if (!leftHeap.isEmpty() && num <= leftHeap.peek()) { + sumLeft -= num; + sizeLeft--; + } else { + sumRight -= num; + sizeRight--; + } + balanceHeaps(); + pruneHeap(leftHeap); + pruneHeap(rightHeap); + } + + private void balanceHeaps() { + if (sizeLeft > sizeRight + 1) { + int num = leftHeap.poll(); + sumLeft -= num; + sizeLeft--; + rightHeap.offer(num); + sumRight += num; + sizeRight++; + } else if (sizeRight > sizeLeft) { + int num = rightHeap.poll(); + sumRight -= num; + sizeRight--; + leftHeap.offer(num); + sumLeft += num; + sizeLeft++; + } + } + + private void pruneHeap(PriorityQueue heap) { + while (!heap.isEmpty() && delayedRemovals.containsKey(heap.peek())) { + int num = heap.peek(); + if (delayedRemovals.get(num) > 0) { + heap.poll(); + delayedRemovals.put(num, delayedRemovals.get(num) - 1); + if (delayedRemovals.get(num) == 0) { + delayedRemovals.remove(num); + } + } else { + break; + } + } + } + + public int getMedian() { + return leftHeap.peek(); + } + + public long getCost() { + int median = getMedian(); + return (long) median * sizeLeft - sumLeft + sumRight - (long) median * sizeRight; + } + } + + public long minOperations(int[] nums, int x, int k) { + int n = nums.length; + int windowCount = n - x + 1; + long[] costs = new long[windowCount]; + SlidingMedian sm = new SlidingMedian(); + // Compute costs for all windows + for (int i = 0; i < x; i++) { + sm.add(nums[i]); + } + costs[0] = sm.getCost(); + for (int i = 1; i < windowCount; i++) { + sm.remove(nums[i - 1]); + sm.add(nums[i + x - 1]); + costs[i] = sm.getCost(); + } + // Dynamic programming table + long[][] dp = new long[windowCount][k + 1]; + for (long[] row : dp) { + Arrays.fill(row, Long.MAX_VALUE / 2); + } + dp[0][0] = 0; + for (int i = 0; i < windowCount; i++) { + for (int j = 0; j <= k; j++) { + if (i > 0) { + dp[i][j] = Math.min(dp[i][j], dp[i - 1][j]); + } + if (j > 0 && i >= x) { + dp[i][j] = Math.min(dp[i][j], dp[i - x][j - 1] + costs[i]); + } else if (j == 1) { + dp[i][j] = Math.min(dp[i][j], costs[i]); + } + } + } + return dp[windowCount - 1][k]; + } +} diff --git a/src/main/java/g3501_3600/s3505_minimum_operations_to_make_elements_within_k_subarrays_equal/readme.md b/src/main/java/g3501_3600/s3505_minimum_operations_to_make_elements_within_k_subarrays_equal/readme.md new file mode 100644 index 000000000..439402d64 --- /dev/null +++ b/src/main/java/g3501_3600/s3505_minimum_operations_to_make_elements_within_k_subarrays_equal/readme.md @@ -0,0 +1,40 @@ +3505\. Minimum Operations to Make Elements Within K Subarrays Equal + +Hard + +You are given an integer array `nums` and two integers, `x` and `k`. You can perform the following operation any number of times (**including zero**): + +* Increase or decrease any element of `nums` by 1. + +Return the **minimum** number of operations needed to have **at least** `k` _non-overlapping **non-empty subarrays**_ of size **exactly** `x` in `nums`, where all elements within each subarray are equal. + +**Example 1:** + +**Input:** nums = [5,-2,1,3,7,3,6,4,-1], x = 3, k = 2 + +**Output:** 8 + +**Explanation:** + +* Use 3 operations to add 3 to `nums[1]` and use 2 operations to subtract 2 from `nums[3]`. The resulting array is `[5, 1, 1, 1, 7, 3, 6, 4, -1]`. +* Use 1 operation to add 1 to `nums[5]` and use 2 operations to subtract 2 from `nums[6]`. The resulting array is `[5, 1, 1, 1, 7, 4, 4, 4, -1]`. +* Now, all elements within each subarray `[1, 1, 1]` (from indices 1 to 3) and `[4, 4, 4]` (from indices 5 to 7) are equal. Since 8 total operations were used, 8 is the output. + +**Example 2:** + +**Input:** nums = [9,-2,-2,-2,1,5], x = 2, k = 2 + +**Output:** 3 + +**Explanation:** + +* Use 3 operations to subtract 3 from `nums[4]`. The resulting array is `[9, -2, -2, -2, -2, 5]`. +* Now, all elements within each subarray `[-2, -2]` (from indices 1 to 2) and `[-2, -2]` (from indices 3 to 4) are equal. Since 3 operations were used, 3 is the output. + +**Constraints:** + +* 2 <= nums.length <= 105 +* -106 <= nums[i] <= 106 +* `2 <= x <= nums.length` +* `1 <= k <= 15` +* `2 <= k * x <= nums.length` \ No newline at end of file diff --git a/src/test/java/g3501_3600/s3502_minimum_cost_to_reach_every_position/SolutionTest.java b/src/test/java/g3501_3600/s3502_minimum_cost_to_reach_every_position/SolutionTest.java new file mode 100644 index 000000000..f35e420d1 --- /dev/null +++ b/src/test/java/g3501_3600/s3502_minimum_cost_to_reach_every_position/SolutionTest.java @@ -0,0 +1,22 @@ +package g3501_3600.s3502_minimum_cost_to_reach_every_position; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void minCosts() { + assertThat( + new Solution().minCosts(new int[] {5, 3, 4, 1, 3, 2}), + equalTo(new int[] {5, 3, 3, 1, 1, 1})); + } + + @Test + void minCosts2() { + assertThat( + new Solution().minCosts(new int[] {1, 2, 4, 6, 7}), + equalTo(new int[] {1, 1, 1, 1, 1})); + } +} diff --git a/src/test/java/g3501_3600/s3503_longest_palindrome_after_substring_concatenation_i/SolutionTest.java b/src/test/java/g3501_3600/s3503_longest_palindrome_after_substring_concatenation_i/SolutionTest.java new file mode 100644 index 000000000..42b8f4c5e --- /dev/null +++ b/src/test/java/g3501_3600/s3503_longest_palindrome_after_substring_concatenation_i/SolutionTest.java @@ -0,0 +1,28 @@ +package g3501_3600.s3503_longest_palindrome_after_substring_concatenation_i; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void longestPalindrome() { + assertThat(new Solution().longestPalindrome("a", "a"), equalTo(2)); + } + + @Test + void longestPalindrome2() { + assertThat(new Solution().longestPalindrome("abc", "def"), equalTo(1)); + } + + @Test + void longestPalindrome3() { + assertThat(new Solution().longestPalindrome("b", "aaaa"), equalTo(4)); + } + + @Test + void longestPalindrome4() { + assertThat(new Solution().longestPalindrome("abcde", "ecdba"), equalTo(5)); + } +} diff --git a/src/test/java/g3501_3600/s3504_longest_palindrome_after_substring_concatenation_ii/SolutionTest.java b/src/test/java/g3501_3600/s3504_longest_palindrome_after_substring_concatenation_ii/SolutionTest.java new file mode 100644 index 000000000..02bffb8e3 --- /dev/null +++ b/src/test/java/g3501_3600/s3504_longest_palindrome_after_substring_concatenation_ii/SolutionTest.java @@ -0,0 +1,28 @@ +package g3501_3600.s3504_longest_palindrome_after_substring_concatenation_ii; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void longestPalindrome() { + assertThat(new Solution().longestPalindrome("a", "a"), equalTo(2)); + } + + @Test + void longestPalindrome2() { + assertThat(new Solution().longestPalindrome("abc", "def"), equalTo(1)); + } + + @Test + void longestPalindrome3() { + assertThat(new Solution().longestPalindrome("b", "aaaa"), equalTo(4)); + } + + @Test + void longestPalindrome4() { + assertThat(new Solution().longestPalindrome("abcde", "ecdba"), equalTo(5)); + } +} diff --git a/src/test/java/g3501_3600/s3505_minimum_operations_to_make_elements_within_k_subarrays_equal/SolutionTest.java b/src/test/java/g3501_3600/s3505_minimum_operations_to_make_elements_within_k_subarrays_equal/SolutionTest.java new file mode 100644 index 000000000..56a825923 --- /dev/null +++ b/src/test/java/g3501_3600/s3505_minimum_operations_to_make_elements_within_k_subarrays_equal/SolutionTest.java @@ -0,0 +1,21 @@ +package g3501_3600.s3505_minimum_operations_to_make_elements_within_k_subarrays_equal; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void minOperations() { + assertThat( + new Solution().minOperations(new int[] {5, -2, 1, 3, 7, 3, 6, 4, -1}, 3, 2), + equalTo(8L)); + } + + @Test + void minOperations2() { + assertThat( + new Solution().minOperations(new int[] {9, -2, -2, -2, 1, 5}, 2, 2), equalTo(3L)); + } +} From aab62d70f731bf354eba4c3bb4d67ddf23a6c26d Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Sun, 30 Mar 2025 18:48:54 +0300 Subject: [PATCH 06/10] Added test --- .../SolutionTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/java/g3501_3600/s3504_longest_palindrome_after_substring_concatenation_ii/SolutionTest.java b/src/test/java/g3501_3600/s3504_longest_palindrome_after_substring_concatenation_ii/SolutionTest.java index 02bffb8e3..846ced21e 100644 --- a/src/test/java/g3501_3600/s3504_longest_palindrome_after_substring_concatenation_ii/SolutionTest.java +++ b/src/test/java/g3501_3600/s3504_longest_palindrome_after_substring_concatenation_ii/SolutionTest.java @@ -25,4 +25,9 @@ void longestPalindrome3() { void longestPalindrome4() { assertThat(new Solution().longestPalindrome("abcde", "ecdba"), equalTo(5)); } + + @Test + void longestPalindrome5() { + assertThat(new Solution().longestPalindrome("xxz", "z"), equalTo(2)); + } } From 559ae5a2945c962a46eb737f026ea42192af6ae9 Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Tue, 1 Apr 2025 13:18:27 +0300 Subject: [PATCH 07/10] Updated tags --- .../Solution.java | 2 +- .../Solution.java | 2 +- .../Solution.java | 74 ++++------------- .../Solution.java | 3 +- .../Solution.java | 2 +- .../Solution.java | 80 ++++++++++++++----- .../Solution.java | 3 +- .../Solution.java | 3 +- 8 files changed, 85 insertions(+), 84 deletions(-) diff --git a/src/main/java/g3401_3500/s3498_reverse_degree_of_a_string/Solution.java b/src/main/java/g3401_3500/s3498_reverse_degree_of_a_string/Solution.java index 09d93d987..230da748a 100644 --- a/src/main/java/g3401_3500/s3498_reverse_degree_of_a_string/Solution.java +++ b/src/main/java/g3401_3500/s3498_reverse_degree_of_a_string/Solution.java @@ -1,6 +1,6 @@ package g3401_3500.s3498_reverse_degree_of_a_string; -// #Easy #2025_03_30_Time_1_ms_(100.00%)_Space_43.05_MB_(100.00%) +// #Easy #String #Simulation #2025_04_01_Time_1_ms_(100.00%)_Space_42.64_MB_(92.21%) public class Solution { public int reverseDegree(String s) { diff --git a/src/main/java/g3401_3500/s3499_maximize_active_section_with_trade_i/Solution.java b/src/main/java/g3401_3500/s3499_maximize_active_section_with_trade_i/Solution.java index 181b8944d..d1ba88bc6 100644 --- a/src/main/java/g3401_3500/s3499_maximize_active_section_with_trade_i/Solution.java +++ b/src/main/java/g3401_3500/s3499_maximize_active_section_with_trade_i/Solution.java @@ -1,6 +1,6 @@ package g3401_3500.s3499_maximize_active_section_with_trade_i; -// #Medium #2025_03_30_Time_55_ms_(100.00%)_Space_45.50_MB_(100.00%) +// #Medium #String #Enumeration #2025_04_01_Time_54_ms_(97.98%)_Space_45.89_MB_(76.19%) public class Solution { public int maxActiveSectionsAfterTrade(String s) { diff --git a/src/main/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/Solution.java b/src/main/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/Solution.java index d7af0b5d8..a94a35d44 100644 --- a/src/main/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/Solution.java +++ b/src/main/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/Solution.java @@ -1,71 +1,31 @@ package g3401_3500.s3500_minimum_cost_to_divide_array_into_subarrays; -// #Hard #2025_03_30_Time_225_ms_(94.64%)_Space_62.54_MB_(58.93%) - -import java.util.Arrays; +// #Hard #Array #Dynamic_Programming #Prefix_Sum +// #2025_04_01_Time_26_ms_(93.46%)_Space_44.97_MB_(94.77%) @SuppressWarnings("java:S107") public class Solution { public long minimumCost(int[] nums, int[] cost, int k) { int n = nums.length; - long[] prefixNums = new long[n]; - long total = 0; - for (int i = 0; i < n; i++) { - total += nums[i]; - prefixNums[i] = total; - } - long[] prefixCost = new long[n + 1]; - total = 0; + long kLong = (long) k; + long[] preNums = new long[n + 1]; + long[] preCost = new long[n + 1]; for (int i = 0; i < n; i++) { - total += cost[i]; - prefixCost[i + 1] = total; - } - long[][] memo = new long[n][n + 1]; - for (long[] row : memo) { - Arrays.fill(row, -1); - } - int[] bestSplit = new int[n]; - Arrays.fill(bestSplit, -1); - return rec(0, 1, nums, prefixNums, prefixCost, k, memo, bestSplit); - } - - private long rec( - int index, - int i, - int[] nums, - long[] prefixNums, - long[] prefixCost, - int k, - long[][] memo, - int[] bestSplit) { - int n = nums.length; - if (index == n) { - return 0; - } - if (memo[index][i] != -1) { - return memo[index][i]; + preNums[i + 1] = preNums[i] + nums[i]; + preCost[i + 1] = preCost[i] + cost[i]; } - if (bestSplit[index] != -1) { - int j = bestSplit[index]; - long val = - (prefixNums[j] + (long) k * i) * (prefixCost[j + 1] - prefixCost[index]) - + rec(j + 1, i + 1, nums, prefixNums, prefixCost, k, memo, bestSplit); - memo[index][i] = val; - return val; + long[] dp = new long[n + 1]; + for (int i = 0; i <= n; i++) { + dp[i] = Long.MAX_VALUE / 2; } - long best = Long.MAX_VALUE; - int bestIndex = -1; - for (int j = index; j < n; j++) { - long val = - (prefixNums[j] + (long) k * i) * (prefixCost[j + 1] - prefixCost[index]) - + rec(j + 1, i + 1, nums, prefixNums, prefixCost, k, memo, bestSplit); - if (val < best) { - best = val; - bestIndex = j; + dp[0] = 0L; + for (int r = 1; r <= n; r++) { + for (int l = 0; l < r; l++) { + long sumNums = preNums[r] * (preCost[r] - preCost[l]); + long sumCost = kLong * (preCost[n] - preCost[l]); + dp[r] = Math.min(dp[r], dp[l] + sumNums + sumCost); } } - bestSplit[index] = bestIndex; - memo[index][i] = best; - return best; + return dp[n]; } } diff --git a/src/main/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/Solution.java b/src/main/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/Solution.java index dab254a8c..8823124cd 100644 --- a/src/main/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/Solution.java +++ b/src/main/java/g3501_3600/s3501_maximize_active_section_with_trade_ii/Solution.java @@ -1,6 +1,7 @@ package g3501_3600.s3501_maximize_active_section_with_trade_ii; -// #Hard #2025_03_30_Time_260_ms_(100.00%)_Space_119.42_MB_(100.00%) +// #Hard #Array #String #Binary_Search #Segment_Tree +// #2025_04_01_Time_256_ms_(63.33%)_Space_106.80_MB_(56.67%) import java.util.ArrayList; import java.util.Arrays; diff --git a/src/main/java/g3501_3600/s3502_minimum_cost_to_reach_every_position/Solution.java b/src/main/java/g3501_3600/s3502_minimum_cost_to_reach_every_position/Solution.java index c60d0bb24..e408695e5 100644 --- a/src/main/java/g3501_3600/s3502_minimum_cost_to_reach_every_position/Solution.java +++ b/src/main/java/g3501_3600/s3502_minimum_cost_to_reach_every_position/Solution.java @@ -1,6 +1,6 @@ package g3501_3600.s3502_minimum_cost_to_reach_every_position; -// #Easy #2025_03_30_Time_1_ms_(97.67%)_Space_44.71_MB_(95.61%) +// #Easy #Array #2025_04_01_Time_1_ms_(97.59%)_Space_44.92_MB_(69.12%) public class Solution { public int[] minCosts(int[] cost) { diff --git a/src/main/java/g3501_3600/s3503_longest_palindrome_after_substring_concatenation_i/Solution.java b/src/main/java/g3501_3600/s3503_longest_palindrome_after_substring_concatenation_i/Solution.java index 72d6e4c62..017c13fe4 100644 --- a/src/main/java/g3501_3600/s3503_longest_palindrome_after_substring_concatenation_i/Solution.java +++ b/src/main/java/g3501_3600/s3503_longest_palindrome_after_substring_concatenation_i/Solution.java @@ -1,37 +1,75 @@ package g3501_3600.s3503_longest_palindrome_after_substring_concatenation_i; -// #Medium #2025_03_30_Time_389_ms_(56.95%)_Space_45.18_MB_(96.47%) +// #Medium #String #Dynamic_Programming #Two_Pointers #Enumeration +// #2025_04_01_Time_30_ms_(97.15%)_Space_42.23_MB_(99.79%) public class Solution { public int longestPalindrome(String s, String t) { - int result = 0; - for (int i = 0; i <= s.length(); i++) { - for (int j = i; j <= s.length(); j++) { - String subStrS = s.substring(i, j); - for (int k = 0; k <= t.length(); k++) { - for (int l = k; l <= t.length(); l++) { - String subStrT = t.substring(k, l); - String combineStr = subStrS + subStrT; - if (isPalindrome(combineStr)) { - result = Math.max(result, combineStr.length()); + int maxLen = 0; + maxLen = Math.max(maxLen, longestPalindromicSubstring(s)); + maxLen = Math.max(maxLen, longestPalindromicSubstring(t)); + int sLen = s.length(); + int tLen = t.length(); + for (int i = 0; i < sLen; i++) { + for (int j = i; j < sLen; j++) { + int m = j - i + 1; + for (int k = 0; k < tLen; k++) { + for (int l = k; l < tLen; l++) { + int n = l - k + 1; + int totalLength = m + n; + if (totalLength <= maxLen) { + continue; + } + boolean isPalindrome = true; + for (int p = 0; p < totalLength / 2; p++) { + int q = totalLength - 1 - p; + char c1, c2; + if (p < m) { + c1 = s.charAt(i + p); + } else { + c1 = t.charAt(k + (p - m)); + } + if (q < m) { + c2 = s.charAt(i + q); + } else { + c2 = t.charAt(k + (q - m)); + } + if (c1 != c2) { + isPalindrome = false; + break; + } + } + if (isPalindrome) { + maxLen = totalLength; } } } } } - return result; + return maxLen; } - private boolean isPalindrome(String input) { - int left = 0; - int right = input.length() - 1; - while (left < right) { - if (input.charAt(left) != input.charAt(right)) { - return false; + private int longestPalindromicSubstring(String str) { + int max = 0; + int len = str.length(); + for (int i = 0; i < len; i++) { + for (int j = i; j < len; j++) { + boolean isPalin = true; + int left = i; + int right = j; + while (left < right) { + if (str.charAt(left) != str.charAt(right)) { + isPalin = false; + break; + } + left++; + right--; + } + if (isPalin) { + max = Math.max(max, j - i + 1); + } } - left++; - right--; } - return true; + return max; } } diff --git a/src/main/java/g3501_3600/s3504_longest_palindrome_after_substring_concatenation_ii/Solution.java b/src/main/java/g3501_3600/s3504_longest_palindrome_after_substring_concatenation_ii/Solution.java index 7893f5458..e74cd9961 100644 --- a/src/main/java/g3501_3600/s3504_longest_palindrome_after_substring_concatenation_ii/Solution.java +++ b/src/main/java/g3501_3600/s3504_longest_palindrome_after_substring_concatenation_ii/Solution.java @@ -1,6 +1,7 @@ package g3501_3600.s3504_longest_palindrome_after_substring_concatenation_ii; -// #Hard #2025_03_30_Time_21_ms_(100.00%)_Space_56.36_MB_(57.78%) +// #Hard #String #Dynamic_Programming #Two_Pointers +// #2025_04_01_Time_25_ms_(99.50%)_Space_52.97_MB_(90.50%) public class Solution { private int[] sPa; diff --git a/src/main/java/g3501_3600/s3505_minimum_operations_to_make_elements_within_k_subarrays_equal/Solution.java b/src/main/java/g3501_3600/s3505_minimum_operations_to_make_elements_within_k_subarrays_equal/Solution.java index 3346d81c8..e72a3c852 100644 --- a/src/main/java/g3501_3600/s3505_minimum_operations_to_make_elements_within_k_subarrays_equal/Solution.java +++ b/src/main/java/g3501_3600/s3505_minimum_operations_to_make_elements_within_k_subarrays_equal/Solution.java @@ -1,6 +1,7 @@ package g3501_3600.s3505_minimum_operations_to_make_elements_within_k_subarrays_equal; -// #Hard #2025_03_30_Time_512_ms_(95.52%)_Space_82.02_MB_(14.18%) +// #Hard #Array #Hash_Table #Dynamic_Programming #Math #Heap_Priority_Queue #Sliding_Window +// #2025_04_01_Time_547_ms_(77.95%)_Space_82.16_MB_(16.92%) import java.util.Arrays; import java.util.Collections; From ed52bd59821f244b34fddc2535e8a1381bf7f5b3 Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Tue, 1 Apr 2025 13:44:00 +0300 Subject: [PATCH 08/10] Fixed embedded-db-junit-jupiter --- build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 767829e41..7081e1e5d 100644 --- a/build.gradle +++ b/build.gradle @@ -12,10 +12,10 @@ repositories { } dependencies { - testImplementation 'org.junit.jupiter:junit-jupiter:[5.11.3,)' + testImplementation 'org.junit.jupiter:junit-jupiter:[5.12.0,)' testImplementation 'org.hamcrest:hamcrest-core:[3.0,)' - testImplementation 'org.zapodot:embedded-db-junit-jupiter:[2.2.0,)' - testRuntimeOnly 'org.junit.platform:junit-platform-launcher:[1.11.3,)' + testImplementation 'org.zapodot:embedded-db-junit-jupiter:2.2.0' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher:[1.12.0,)' } test { From 603ec1dd77f396dadaa45947281b62f3c21c5093 Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Tue, 1 Apr 2025 13:58:05 +0300 Subject: [PATCH 09/10] Fixed style --- .../Solution.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/g3501_3600/s3503_longest_palindrome_after_substring_concatenation_i/Solution.java b/src/main/java/g3501_3600/s3503_longest_palindrome_after_substring_concatenation_i/Solution.java index 017c13fe4..ea31e6d0d 100644 --- a/src/main/java/g3501_3600/s3503_longest_palindrome_after_substring_concatenation_i/Solution.java +++ b/src/main/java/g3501_3600/s3503_longest_palindrome_after_substring_concatenation_i/Solution.java @@ -23,7 +23,8 @@ public int longestPalindrome(String s, String t) { boolean isPalindrome = true; for (int p = 0; p < totalLength / 2; p++) { int q = totalLength - 1 - p; - char c1, c2; + char c1; + char c2; if (p < m) { c1 = s.charAt(i + p); } else { From a618fb45f872744758dca5f418c69579bd348e6b Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Tue, 1 Apr 2025 13:59:50 +0300 Subject: [PATCH 10/10] Fixed sonar --- .../Solution.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/Solution.java b/src/main/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/Solution.java index a94a35d44..b52cf7870 100644 --- a/src/main/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/Solution.java +++ b/src/main/java/g3401_3500/s3500_minimum_cost_to_divide_array_into_subarrays/Solution.java @@ -7,7 +7,7 @@ public class Solution { public long minimumCost(int[] nums, int[] cost, int k) { int n = nums.length; - long kLong = (long) k; + long kLong = k; long[] preNums = new long[n + 1]; long[] preCost = new long[n + 1]; for (int i = 0; i < n; i++) {