From 3a86f28b2f6e0a562364df5c7223d5100474f2cd Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Mon, 16 Jun 2025 03:35:04 +0300 Subject: [PATCH 1/4] Added tasks 3582-3585 --- .../Solution.java | 32 +++++ .../readme.md | 51 ++++++++ .../Solution.java | 26 ++++ .../s3583_count_special_triplets/readme.md | 67 ++++++++++ .../Solution.java | 17 +++ .../readme.md | 43 ++++++ .../Solution.java | 122 ++++++++++++++++++ .../readme.md | 70 ++++++++++ .../SolutionTest.java | 34 +++++ .../SolutionTest.java | 23 ++++ .../SolutionTest.java | 27 ++++ .../SolutionTest.java | 37 ++++++ 12 files changed, 549 insertions(+) create mode 100644 src/main/java/g3501_3600/s3582_generate_tag_for_video_caption/Solution.java create mode 100644 src/main/java/g3501_3600/s3582_generate_tag_for_video_caption/readme.md create mode 100644 src/main/java/g3501_3600/s3583_count_special_triplets/Solution.java create mode 100644 src/main/java/g3501_3600/s3583_count_special_triplets/readme.md create mode 100644 src/main/java/g3501_3600/s3584_maximum_product_of_first_and_last_elements_of_a_subsequence/Solution.java create mode 100644 src/main/java/g3501_3600/s3584_maximum_product_of_first_and_last_elements_of_a_subsequence/readme.md create mode 100644 src/main/java/g3501_3600/s3585_find_weighted_median_node_in_tree/Solution.java create mode 100644 src/main/java/g3501_3600/s3585_find_weighted_median_node_in_tree/readme.md create mode 100644 src/test/java/g3501_3600/s3582_generate_tag_for_video_caption/SolutionTest.java create mode 100644 src/test/java/g3501_3600/s3583_count_special_triplets/SolutionTest.java create mode 100644 src/test/java/g3501_3600/s3584_maximum_product_of_first_and_last_elements_of_a_subsequence/SolutionTest.java create mode 100644 src/test/java/g3501_3600/s3585_find_weighted_median_node_in_tree/SolutionTest.java diff --git a/src/main/java/g3501_3600/s3582_generate_tag_for_video_caption/Solution.java b/src/main/java/g3501_3600/s3582_generate_tag_for_video_caption/Solution.java new file mode 100644 index 000000000..3fbc17d44 --- /dev/null +++ b/src/main/java/g3501_3600/s3582_generate_tag_for_video_caption/Solution.java @@ -0,0 +1,32 @@ +package g3501_3600.s3582_generate_tag_for_video_caption; + +// #Easy #2025_06_16_Time_12_ms_(100.00%)_Space_45.47_MB_(100.00%) + +public class Solution { + public String generateTag(String caption) { + if (caption.trim().isEmpty()) { + return "#"; + } + String[] arr = caption.trim().split("\\s+"); + StringBuilder res = new StringBuilder("#"); + String firstWord = arr[0]; + firstWord = + firstWord.substring(0, 1).toLowerCase() + + (firstWord.length() > 1 ? firstWord.substring(1).toLowerCase() : ""); + res.append(firstWord); + for (int i = 1; i < arr.length; i++) { + String w = arr[i]; + if (w.isEmpty()) { + continue; + } + w = + w.substring(0, 1).toUpperCase() + + (w.length() > 1 ? w.substring(1).toLowerCase() : ""); + res.append(w); + if (res.length() >= 100) { + break; + } + } + return res.length() > 100 ? res.substring(0, 100) : res.toString(); + } +} diff --git a/src/main/java/g3501_3600/s3582_generate_tag_for_video_caption/readme.md b/src/main/java/g3501_3600/s3582_generate_tag_for_video_caption/readme.md new file mode 100644 index 000000000..d64fccb68 --- /dev/null +++ b/src/main/java/g3501_3600/s3582_generate_tag_for_video_caption/readme.md @@ -0,0 +1,51 @@ +3582\. Generate Tag for Video Caption + +Easy + +You are given a string `caption` representing the caption for a video. + +The following actions must be performed **in order** to generate a **valid tag** for the video: + +1. **Combine all words** in the string into a single _camelCase string_ prefixed with `'#'`. A _camelCase string_ is one where the first letter of all words _except_ the first one is capitalized. All characters after the first character in **each** word must be lowercase. + +2. **Remove** all characters that are not an English letter, **except** the first `'#'`. + +3. **Truncate** the result to a maximum of 100 characters. + + +Return the **tag** after performing the actions on `caption`. + +**Example 1:** + +**Input:** caption = "Leetcode daily streak achieved" + +**Output:** "#leetcodeDailyStreakAchieved" + +**Explanation:** + +The first letter for all words except `"leetcode"` should be capitalized. + +**Example 2:** + +**Input:** caption = "can I Go There" + +**Output:** "#canIGoThere" + +**Explanation:** + +The first letter for all words except `"can"` should be capitalized. + +**Example 3:** + +**Input:** caption = "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh" + +**Output:** "#hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh" + +**Explanation:** + +Since the first word has length 101, we need to truncate the last two letters from the word. + +**Constraints:** + +* `1 <= caption.length <= 150` +* `caption` consists only of English letters and `' '`. \ No newline at end of file diff --git a/src/main/java/g3501_3600/s3583_count_special_triplets/Solution.java b/src/main/java/g3501_3600/s3583_count_special_triplets/Solution.java new file mode 100644 index 000000000..d80148a83 --- /dev/null +++ b/src/main/java/g3501_3600/s3583_count_special_triplets/Solution.java @@ -0,0 +1,26 @@ +package g3501_3600.s3583_count_special_triplets; + +// #Medium #2025_06_16_Time_250_ms_(100.00%)_Space_62.22_MB_(100.00%) + +import java.util.HashMap; +import java.util.Map; + +public class Solution { + public int specialTriplets(int[] nums) { + int mod = 1_000_000_007; + int res = 0; + Map left = new HashMap<>(); + Map right = new HashMap<>(); + for (int num : nums) { + right.put(num, right.getOrDefault(num, 0) + 1); + } + for (int num : nums) { + right.put(num, right.get(num) - 1); + int ci = left.getOrDefault(num * 2, 0); + int ck = right.getOrDefault(num * 2, 0); + res = (res + ci * ck) % mod; + left.put(num, left.getOrDefault(num, 0) + 1); + } + return res; + } +} diff --git a/src/main/java/g3501_3600/s3583_count_special_triplets/readme.md b/src/main/java/g3501_3600/s3583_count_special_triplets/readme.md new file mode 100644 index 000000000..3f704fb0b --- /dev/null +++ b/src/main/java/g3501_3600/s3583_count_special_triplets/readme.md @@ -0,0 +1,67 @@ +3583\. Count Special Triplets + +Medium + +You are given an integer array `nums`. + +A **special triplet** is defined as a triplet of indices `(i, j, k)` such that: + +* `0 <= i < j < k < n`, where `n = nums.length` +* `nums[i] == nums[j] * 2` +* `nums[k] == nums[j] * 2` + +Return the total number of **special triplets** in the array. + +Since the answer may be large, return it **modulo** 109 + 7. + +**Example 1:** + +**Input:** nums = [6,3,6] + +**Output:** 1 + +**Explanation:** + +The only special triplet is `(i, j, k) = (0, 1, 2)`, where: + +* `nums[0] = 6`, `nums[1] = 3`, `nums[2] = 6` +* `nums[0] = nums[1] * 2 = 3 * 2 = 6` +* `nums[2] = nums[1] * 2 = 3 * 2 = 6` + +**Example 2:** + +**Input:** nums = [0,1,0,0] + +**Output:** 1 + +**Explanation:** + +The only special triplet is `(i, j, k) = (0, 2, 3)`, where: + +* `nums[0] = 0`, `nums[2] = 0`, `nums[3] = 0` +* `nums[0] = nums[2] * 2 = 0 * 2 = 0` +* `nums[3] = nums[2] * 2 = 0 * 2 = 0` + +**Example 3:** + +**Input:** nums = [8,4,2,8,4] + +**Output:** 2 + +**Explanation:** + +There are exactly two special triplets: + +* `(i, j, k) = (0, 1, 3)` + * `nums[0] = 8`, `nums[1] = 4`, `nums[3] = 8` + * `nums[0] = nums[1] * 2 = 4 * 2 = 8` + * `nums[3] = nums[1] * 2 = 4 * 2 = 8` +* `(i, j, k) = (1, 2, 4)` + * `nums[1] = 4`, `nums[2] = 2`, `nums[4] = 4` + * `nums[1] = nums[2] * 2 = 2 * 2 = 4` + * `nums[4] = nums[2] * 2 = 2 * 2 = 4` + +**Constraints:** + +* 3 <= n == nums.length <= 105 +* 0 <= nums[i] <= 105 \ No newline at end of file diff --git a/src/main/java/g3501_3600/s3584_maximum_product_of_first_and_last_elements_of_a_subsequence/Solution.java b/src/main/java/g3501_3600/s3584_maximum_product_of_first_and_last_elements_of_a_subsequence/Solution.java new file mode 100644 index 000000000..651d2928b --- /dev/null +++ b/src/main/java/g3501_3600/s3584_maximum_product_of_first_and_last_elements_of_a_subsequence/Solution.java @@ -0,0 +1,17 @@ +package g3501_3600.s3584_maximum_product_of_first_and_last_elements_of_a_subsequence; + +// #Medium #2025_06_16_Time_4_ms_(87.17%)_Space_61.31_MB_(100.00%) + +public class Solution { + public long maximumProduct(int[] nums, int m) { + long ma = nums[0]; + long mi = nums[0]; + long res = (long) nums[0] * nums[m - 1]; + for (int i = m - 1; i < nums.length; ++i) { + ma = Math.max(ma, nums[i - m + 1]); + mi = Math.min(mi, nums[i - m + 1]); + res = Math.max(res, Math.max(mi * nums[i], ma * nums[i])); + } + return res; + } +} diff --git a/src/main/java/g3501_3600/s3584_maximum_product_of_first_and_last_elements_of_a_subsequence/readme.md b/src/main/java/g3501_3600/s3584_maximum_product_of_first_and_last_elements_of_a_subsequence/readme.md new file mode 100644 index 000000000..45bcb13ad --- /dev/null +++ b/src/main/java/g3501_3600/s3584_maximum_product_of_first_and_last_elements_of_a_subsequence/readme.md @@ -0,0 +1,43 @@ +3584\. Maximum Product of First and Last Elements of a Subsequence + +Medium + +You are given an integer array `nums` and an integer `m`. + +Return the **maximum** product of the first and last elements of any ****subsequences**** of `nums` of size `m`. + +**Example 1:** + +**Input:** nums = [-1,-9,2,3,-2,-3,1], m = 1 + +**Output:** 81 + +**Explanation:** + +The subsequence `[-9]` has the largest product of the first and last elements: `-9 * -9 = 81`. Therefore, the answer is 81. + +**Example 2:** + +**Input:** nums = [1,3,-5,5,6,-4], m = 3 + +**Output:** 20 + +**Explanation:** + +The subsequence `[-5, 6, -4]` has the largest product of the first and last elements. + +**Example 3:** + +**Input:** nums = [2,-1,2,-6,5,2,-5,7], m = 2 + +**Output:** 35 + +**Explanation:** + +The subsequence `[5, 7]` has the largest product of the first and last elements. + +**Constraints:** + +* 1 <= nums.length <= 105 +* -105 <= nums[i] <= 105 +* `1 <= m <= nums.length` \ No newline at end of file diff --git a/src/main/java/g3501_3600/s3585_find_weighted_median_node_in_tree/Solution.java b/src/main/java/g3501_3600/s3585_find_weighted_median_node_in_tree/Solution.java new file mode 100644 index 000000000..075ce1a9b --- /dev/null +++ b/src/main/java/g3501_3600/s3585_find_weighted_median_node_in_tree/Solution.java @@ -0,0 +1,122 @@ +package g3501_3600.s3585_find_weighted_median_node_in_tree; + +// #Hard #2025_06_16_Time_162_ms_(100.00%)_Space_141.58_MB_(100.00%) + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class Solution { + private int log; + private long[] dist; + private int[] depth; + private int[][] up; + + public int[] findMedian(int n, int[][] edges, int[][] queries) { + List> adj = new ArrayList<>(); + for (int i = 0; i < n; i++) { + adj.add(new ArrayList<>()); + } + for (int[] edge : edges) { + adj.get(edge[0]).add(new int[] {edge[1], edge[2]}); + adj.get(edge[1]).add(new int[] {edge[0], edge[2]}); + } + dist = new long[n]; + depth = new int[n]; + log = 0; + while (1 << log < n) { + log++; + } + up = new int[n][log]; + for (int[] u : up) { + Arrays.fill(u, -1); + } + dfs(0, -1, adj, 0, 0); + int[] ans = new int[queries.length]; + for (int i = 0; i < queries.length; i++) { + int[] query = queries[i]; + int first = query[0]; + int second = query[1]; + long distance = getDistance(first, second); + long needed = (distance + 1) / 2; + int mid = lca(first, second); + if (getDistance(first, mid) < needed) { + needed -= getDistance(first, mid); + first = mid; + } else { + second = mid; + } + if (depth[first] <= depth[second]) { + long curDistance = getDistance(first, second); + for (int j = log - 1; j >= 0; j--) { + if (up[second][j] == -1 + || curDistance - getDistance(up[second][j], second) < needed) { + continue; + } + curDistance -= getDistance(up[second][j], second); + second = up[second][j]; + } + ans[i] = second; + } else { + long curDistance = 0; + for (int j = log - 1; j >= 0; j--) { + if (up[first][j] == -1 + || curDistance + getDistance(up[first][j], first) >= needed) { + continue; + } + curDistance += getDistance(up[first][j], first); + first = up[first][j]; + } + ans[i] = up[first][0]; + } + } + return ans; + } + + private long getDistance(int from, int to) { + if (from == to) { + return 0; + } + int ancesor = lca(from, to); + return dist[from] + dist[to] - 2 * dist[ancesor]; + } + + private int lca(int first, int second) { + if (depth[first] < depth[second]) { + return lca(second, first); + } + for (int i = log - 1; i >= 0; i--) { + if (depth[first] - (1 << i) >= depth[second]) { + first = up[first][i]; + } + } + if (first == second) { + return second; + } + for (int i = log - 1; i >= 0; i--) { + if (depth[first] != -1 && up[first][i] != up[second][i]) { + first = up[first][i]; + second = up[second][i]; + } + } + first = up[first][0]; + return first; + } + + private void dfs(int current, int parent, List> adj, long curDist, int curDepth) { + up[current][0] = parent; + for (int i = 1; i < log; i++) { + if (up[current][i - 1] != -1) { + up[current][i] = up[up[current][i - 1]][i - 1]; + } + } + dist[current] = curDist; + depth[current] = curDepth; + for (int[] next : adj.get(current)) { + if (next[0] == parent) { + continue; + } + dfs(next[0], current, adj, curDist + next[1], curDepth + 1); + } + } +} diff --git a/src/main/java/g3501_3600/s3585_find_weighted_median_node_in_tree/readme.md b/src/main/java/g3501_3600/s3585_find_weighted_median_node_in_tree/readme.md new file mode 100644 index 000000000..69a344aa8 --- /dev/null +++ b/src/main/java/g3501_3600/s3585_find_weighted_median_node_in_tree/readme.md @@ -0,0 +1,70 @@ +3585\. Find Weighted Median Node in Tree + +Hard + +You are given an integer `n` and an **undirected, weighted** tree rooted at node 0 with `n` nodes numbered from 0 to `n - 1`. This is represented by a 2D array `edges` of length `n - 1`, where edges[i] = [ui, vi, wi] indicates an edge from node ui to vi with weight wi. + +The **weighted median node** is defined as the **first** node `x` on the path from ui to vi such that the sum of edge weights from ui to `x` is **greater than or equal to half** of the total path weight. + +You are given a 2D integer array `queries`. For each queries[j] = [uj, vj], determine the weighted median node along the path from uj to vj. + +Return an array `ans`, where `ans[j]` is the node index of the weighted median for `queries[j]`. + +**Example 1:** + +**Input:** n = 2, edges = [[0,1,7]], queries = [[1,0],[0,1]] + +**Output:** [0,1] + +**Explanation:** + +![](https://assets.leetcode.com/uploads/2025/05/26/screenshot-2025-05-26-at-193447.png) + +| Query | Path | Edge Weights | Total Path Weight | Half | Explanation | Answer | +|------------|----------|---------------|--------------------|------|-------------------------------------------------------|--------| +| `[1, 0]` | `1 → 0` | `[7]` | 7 | 3.5 | Sum from `1 → 0 = 7 >= 3.5`, median is node 0. | 0 | +| `[0, 1]` | `0 → 1` | `[7]` | 7 | 3.5 | Sum from `0 → 1 = 7 >= 3.5`, median is node 1. | 1 | + + +**Example 2:** + +**Input:** n = 3, edges = [[0,1,2],[2,0,4]], queries = [[0,1],[2,0],[1,2]] + +**Output:** [1,0,2] + +**E****xplanation:** + +![](https://assets.leetcode.com/uploads/2025/05/26/screenshot-2025-05-26-at-193610.png) + +| Query | Path | Edge Weights | Total Path Weight | Half | Explanation | Answer | +|------------|--------------|--------------|--------------------|------|-----------------------------------------------------------------------------|--------| +| `[0, 1]` | `0 → 1` | `[2]` | 2 | 1 | Sum from `0 → 1 = 2 >= 1`, median is node 1. | 1 | +| `[2, 0]` | `2 → 0` | `[4]` | 4 | 2 | Sum from `2 → 0 = 4 >= 2`, median is node 0. | 0 | +| `[1, 2]` | `1 → 0 → 2` | `[2, 4]` | 6 | 3 | Sum from `1 → 0 = 2 < 3`.
Sum from `1 → 2 = 2 + 4 = 6 >= 3`, median is node 2. | 2 | + +**Example 3:** + +**Input:** n = 5, edges = [[0,1,2],[0,2,5],[1,3,1],[2,4,3]], queries = [[3,4],[1,2]] + +**Output:** [2,2] + +**Explanation:** + +![](https://assets.leetcode.com/uploads/2025/05/26/screenshot-2025-05-26-at-193857.png) + +| Query | Path | Edge Weights | Total Path Weight | Half | Explanation | Answer | +|------------|----------------------|------------------|--------------------|------|-----------------------------------------------------------------------------------------------------------------------------------------------------|--------| +| `[3, 4]` | `3 → 1 → 0 → 2 → 4` | `[1, 2, 5, 3]` | 11 | 5.5 | Sum from `3 → 1 = 1 < 5.5`.
Sum from `3 → 0 = 1 + 2 = 3 < 5.5`.
Sum from `3 → 2 = 1 + 2 + 5 = 8 >= 5.5`, median is node 2. | 2 | +| `[1, 2]` | `1 → 0 → 2` | `[2, 5]` | 7 | 3.5 | Sum from `1 → 0 = 2 < 3.5`.
Sum from `1 → 2 = 2 + 5 = 7 >= 3.5`, median is node 2. | 2 | + +**Constraints:** + +* 2 <= n <= 105 +* `edges.length == n - 1` +* edges[i] == [ui, vi, wi] +* 0 <= ui, vi < n +* 1 <= wi <= 109 +* 1 <= queries.length <= 105 +* queries[j] == [uj, vj] +* 0 <= uj, vj < n +* The input is generated such that `edges` represents a valid tree. \ No newline at end of file diff --git a/src/test/java/g3501_3600/s3582_generate_tag_for_video_caption/SolutionTest.java b/src/test/java/g3501_3600/s3582_generate_tag_for_video_caption/SolutionTest.java new file mode 100644 index 000000000..2317a9b1c --- /dev/null +++ b/src/test/java/g3501_3600/s3582_generate_tag_for_video_caption/SolutionTest.java @@ -0,0 +1,34 @@ +package g3501_3600.s3582_generate_tag_for_video_caption; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void generateTag() { + assertThat( + new Solution().generateTag("Leetcode daily streak achieved"), + equalTo("#leetcodeDailyStreakAchieved")); + } + + @Test + void generateTag2() { + assertThat(new Solution().generateTag("can I Go There"), equalTo("#canIGoThere")); + } + + @Test + void generateTag3() { + assertThat( + new Solution() + .generateTag( + "hhhhhhhhhhhhhhhhhhhhh" + + "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhh" + + "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"), + equalTo( + "#hhhhhhhhhhhhhhhhhhh" + + "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh" + + "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")); + } +} diff --git a/src/test/java/g3501_3600/s3583_count_special_triplets/SolutionTest.java b/src/test/java/g3501_3600/s3583_count_special_triplets/SolutionTest.java new file mode 100644 index 000000000..0ed4aed0e --- /dev/null +++ b/src/test/java/g3501_3600/s3583_count_special_triplets/SolutionTest.java @@ -0,0 +1,23 @@ +package g3501_3600.s3583_count_special_triplets; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void specialTriplets() { + assertThat(new Solution().specialTriplets(new int[] {6, 3, 6}), equalTo(1)); + } + + @Test + void specialTriplets2() { + assertThat(new Solution().specialTriplets(new int[] {0, 1, 0, 0}), equalTo(1)); + } + + @Test + void specialTriplets3() { + assertThat(new Solution().specialTriplets(new int[] {8, 4, 2, 8, 4}), equalTo(2)); + } +} diff --git a/src/test/java/g3501_3600/s3584_maximum_product_of_first_and_last_elements_of_a_subsequence/SolutionTest.java b/src/test/java/g3501_3600/s3584_maximum_product_of_first_and_last_elements_of_a_subsequence/SolutionTest.java new file mode 100644 index 000000000..02c6969b5 --- /dev/null +++ b/src/test/java/g3501_3600/s3584_maximum_product_of_first_and_last_elements_of_a_subsequence/SolutionTest.java @@ -0,0 +1,27 @@ +package g3501_3600.s3584_maximum_product_of_first_and_last_elements_of_a_subsequence; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void maximumProduct() { + assertThat( + new Solution().maximumProduct(new int[] {-1, -9, 2, 3, -2, -3, 1}, 1), + equalTo(81L)); + } + + @Test + void maximumProduct2() { + assertThat(new Solution().maximumProduct(new int[] {1, 3, -5, 5, 6, -4}, 3), equalTo(20L)); + } + + @Test + void maximumProduct3() { + assertThat( + new Solution().maximumProduct(new int[] {2, -1, 2, -6, 5, 2, -5, 7}, 2), + equalTo(35L)); + } +} diff --git a/src/test/java/g3501_3600/s3585_find_weighted_median_node_in_tree/SolutionTest.java b/src/test/java/g3501_3600/s3585_find_weighted_median_node_in_tree/SolutionTest.java new file mode 100644 index 000000000..17b6f71b1 --- /dev/null +++ b/src/test/java/g3501_3600/s3585_find_weighted_median_node_in_tree/SolutionTest.java @@ -0,0 +1,37 @@ +package g3501_3600.s3585_find_weighted_median_node_in_tree; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void findMedian() { + assertThat( + new Solution().findMedian(2, new int[][] {{0, 1, 7}}, new int[][] {{1, 0}, {0, 1}}), + equalTo(new int[] {0, 1})); + } + + @Test + void findMedian2() { + assertThat( + new Solution() + .findMedian( + 3, + new int[][] {{0, 1, 2}, {2, 0, 4}}, + new int[][] {{0, 1}, {2, 0}, {1, 2}}), + equalTo(new int[] {1, 0, 2})); + } + + @Test + void findMedian3() { + assertThat( + new Solution() + .findMedian( + 5, + new int[][] {{0, 1, 2}, {0, 2, 5}, {1, 3, 1}, {2, 4, 3}}, + new int[][] {{3, 4}, {1, 2}}), + equalTo(new int[] {2, 2})); + } +} From 8cba34411da0db770229572ef9d220b848f36f92 Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Mon, 16 Jun 2025 03:41:00 +0300 Subject: [PATCH 2/4] Fixed sonar --- .../s3582_generate_tag_for_video_caption/Solution.java | 1 + .../s3585_find_weighted_median_node_in_tree/Solution.java | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/java/g3501_3600/s3582_generate_tag_for_video_caption/Solution.java b/src/main/java/g3501_3600/s3582_generate_tag_for_video_caption/Solution.java index 3fbc17d44..57a37e277 100644 --- a/src/main/java/g3501_3600/s3582_generate_tag_for_video_caption/Solution.java +++ b/src/main/java/g3501_3600/s3582_generate_tag_for_video_caption/Solution.java @@ -2,6 +2,7 @@ // #Easy #2025_06_16_Time_12_ms_(100.00%)_Space_45.47_MB_(100.00%) +@SuppressWarnings("java:S135") public class Solution { public String generateTag(String caption) { if (caption.trim().isEmpty()) { diff --git a/src/main/java/g3501_3600/s3585_find_weighted_median_node_in_tree/Solution.java b/src/main/java/g3501_3600/s3585_find_weighted_median_node_in_tree/Solution.java index 075ce1a9b..d5eb828c2 100644 --- a/src/main/java/g3501_3600/s3585_find_weighted_median_node_in_tree/Solution.java +++ b/src/main/java/g3501_3600/s3585_find_weighted_median_node_in_tree/Solution.java @@ -6,6 +6,7 @@ import java.util.Arrays; import java.util.List; +@SuppressWarnings("java:S2234") public class Solution { private int log; private long[] dist; From 1811863299f2570e4c10ab91358bad8d1c6634c8 Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Tue, 17 Jun 2025 07:59:01 +0300 Subject: [PATCH 3/4] Updated tags --- .../Solution.java | 51 ++--- .../Solution.java | 33 ++-- .../Solution.java | 2 +- .../Solution.java | 185 ++++++++++-------- 4 files changed, 147 insertions(+), 124 deletions(-) diff --git a/src/main/java/g3501_3600/s3582_generate_tag_for_video_caption/Solution.java b/src/main/java/g3501_3600/s3582_generate_tag_for_video_caption/Solution.java index 57a37e277..0c6d233d1 100644 --- a/src/main/java/g3501_3600/s3582_generate_tag_for_video_caption/Solution.java +++ b/src/main/java/g3501_3600/s3582_generate_tag_for_video_caption/Solution.java @@ -1,33 +1,38 @@ package g3501_3600.s3582_generate_tag_for_video_caption; -// #Easy #2025_06_16_Time_12_ms_(100.00%)_Space_45.47_MB_(100.00%) +// #Easy #String #Simulation #2025_06_17_Time_2_ms_(99.93%)_Space_43.54_MB_(89.89%) -@SuppressWarnings("java:S135") public class Solution { public String generateTag(String caption) { - if (caption.trim().isEmpty()) { - return "#"; - } - String[] arr = caption.trim().split("\\s+"); - StringBuilder res = new StringBuilder("#"); - String firstWord = arr[0]; - firstWord = - firstWord.substring(0, 1).toLowerCase() - + (firstWord.length() > 1 ? firstWord.substring(1).toLowerCase() : ""); - res.append(firstWord); - for (int i = 1; i < arr.length; i++) { - String w = arr[i]; - if (w.isEmpty()) { - continue; + StringBuilder sb = new StringBuilder(); + sb.append('#'); + boolean space = false; + caption = caption.trim(); + for (int i = 0; i < caption.length(); i++) { + char c = caption.charAt(i); + if (c == ' ') { + space = true; + } + if (c >= 'A' && c <= 'Z') { + if (space) { + space = !space; + sb.append(c); + } else { + sb.append(Character.toLowerCase(c)); + } } - w = - w.substring(0, 1).toUpperCase() - + (w.length() > 1 ? w.substring(1).toLowerCase() : ""); - res.append(w); - if (res.length() >= 100) { - break; + if (c >= 'a' && c <= 'z') { + if (space) { + space = !space; + sb.append(Character.toUpperCase(c)); + } else { + sb.append(c); + } } } - return res.length() > 100 ? res.substring(0, 100) : res.toString(); + if (sb.length() > 100) { + return sb.substring(0, 100); + } + return sb.toString(); } } diff --git a/src/main/java/g3501_3600/s3583_count_special_triplets/Solution.java b/src/main/java/g3501_3600/s3583_count_special_triplets/Solution.java index d80148a83..e00bf0ea2 100644 --- a/src/main/java/g3501_3600/s3583_count_special_triplets/Solution.java +++ b/src/main/java/g3501_3600/s3583_count_special_triplets/Solution.java @@ -1,26 +1,25 @@ package g3501_3600.s3583_count_special_triplets; -// #Medium #2025_06_16_Time_250_ms_(100.00%)_Space_62.22_MB_(100.00%) - -import java.util.HashMap; -import java.util.Map; +// #Medium #Array #Hash_Table #Counting #2025_06_17_Time_30_ms_(99.81%)_Space_60.90_MB_(89.67%) public class Solution { public int specialTriplets(int[] nums) { - int mod = 1_000_000_007; - int res = 0; - Map left = new HashMap<>(); - Map right = new HashMap<>(); - for (int num : nums) { - right.put(num, right.getOrDefault(num, 0) + 1); + long ans = 0; + int[] sum = new int[200002]; + int[] left = new int[nums.length]; + for (int i = 0; i < nums.length; i++) { + int curr = nums[i]; + sum[curr]++; + left[i] = sum[curr * 2]; } - for (int num : nums) { - right.put(num, right.get(num) - 1); - int ci = left.getOrDefault(num * 2, 0); - int ck = right.getOrDefault(num * 2, 0); - res = (res + ci * ck) % mod; - left.put(num, left.getOrDefault(num, 0) + 1); + for (int i = 0; i < nums.length; i++) { + int curr = nums[i]; + long leftCount = curr == 0 ? left[i] - 1 : left[i]; + long rightCount = sum[curr * 2] - left[i]; + if (leftCount != 0 && rightCount != 0) { + ans += leftCount * rightCount; + } } - return res; + return (int) (ans % 1000000007); } } diff --git a/src/main/java/g3501_3600/s3584_maximum_product_of_first_and_last_elements_of_a_subsequence/Solution.java b/src/main/java/g3501_3600/s3584_maximum_product_of_first_and_last_elements_of_a_subsequence/Solution.java index 651d2928b..793f3c086 100644 --- a/src/main/java/g3501_3600/s3584_maximum_product_of_first_and_last_elements_of_a_subsequence/Solution.java +++ b/src/main/java/g3501_3600/s3584_maximum_product_of_first_and_last_elements_of_a_subsequence/Solution.java @@ -1,6 +1,6 @@ package g3501_3600.s3584_maximum_product_of_first_and_last_elements_of_a_subsequence; -// #Medium #2025_06_16_Time_4_ms_(87.17%)_Space_61.31_MB_(100.00%) +// #Medium #Array #Two_Pointers #2025_06_17_Time_4_ms_(86.42%)_Space_60.92_MB_(51.72%) public class Solution { public long maximumProduct(int[] nums, int m) { diff --git a/src/main/java/g3501_3600/s3585_find_weighted_median_node_in_tree/Solution.java b/src/main/java/g3501_3600/s3585_find_weighted_median_node_in_tree/Solution.java index d5eb828c2..a8fcda48e 100644 --- a/src/main/java/g3501_3600/s3585_find_weighted_median_node_in_tree/Solution.java +++ b/src/main/java/g3501_3600/s3585_find_weighted_median_node_in_tree/Solution.java @@ -1,6 +1,7 @@ package g3501_3600.s3585_find_weighted_median_node_in_tree; -// #Hard #2025_06_16_Time_162_ms_(100.00%)_Space_141.58_MB_(100.00%) +// #Hard #Array #Dynamic_Programming #Tree #Binary_Search #Depth_First_Search +// #2025_06_17_Time_66_ms_(94.96%)_Space_142.62_MB_(49.64%) import java.util.ArrayList; import java.util.Arrays; @@ -8,116 +9,134 @@ @SuppressWarnings("java:S2234") public class Solution { - private int log; - private long[] dist; + private List> adj; private int[] depth; - private int[][] up; + private long[] dist; + private int[][] parent; + private int longMax; + private int nodes; public int[] findMedian(int n, int[][] edges, int[][] queries) { - List> adj = new ArrayList<>(); + nodes = n; + if (n > 1) { + longMax = (int) Math.ceil(Math.log(n) / Math.log(2)); + } else { + longMax = 1; + } + adj = new ArrayList<>(); for (int i = 0; i < n; i++) { adj.add(new ArrayList<>()); } for (int[] edge : edges) { - adj.get(edge[0]).add(new int[] {edge[1], edge[2]}); - adj.get(edge[1]).add(new int[] {edge[0], edge[2]}); + int u = edge[0]; + int v = edge[1]; + int w = edge[2]; + adj.get(u).add(new int[] {v, w}); + adj.get(v).add(new int[] {u, w}); } - dist = new long[n]; depth = new int[n]; - log = 0; - while (1 << log < n) { - log++; - } - up = new int[n][log]; - for (int[] u : up) { - Arrays.fill(u, -1); + dist = new long[n]; + parent = new int[longMax][n]; + for (int i = 0; i < longMax; i++) { + Arrays.fill(parent[i], -1); } - dfs(0, -1, adj, 0, 0); + dfs(0, -1, 0, 0L); + buildLcaTable(); int[] ans = new int[queries.length]; - for (int i = 0; i < queries.length; i++) { - int[] query = queries[i]; - int first = query[0]; - int second = query[1]; - long distance = getDistance(first, second); - long needed = (distance + 1) / 2; - int mid = lca(first, second); - if (getDistance(first, mid) < needed) { - needed -= getDistance(first, mid); - first = mid; - } else { - second = mid; - } - if (depth[first] <= depth[second]) { - long curDistance = getDistance(first, second); - for (int j = log - 1; j >= 0; j--) { - if (up[second][j] == -1 - || curDistance - getDistance(up[second][j], second) < needed) { - continue; - } - curDistance -= getDistance(up[second][j], second); - second = up[second][j]; - } - ans[i] = second; - } else { - long curDistance = 0; - for (int j = log - 1; j >= 0; j--) { - if (up[first][j] == -1 - || curDistance + getDistance(up[first][j], first) >= needed) { - continue; - } - curDistance += getDistance(up[first][j], first); - first = up[first][j]; - } - ans[i] = up[first][0]; - } + int[] sabrelonta; + for (int qIdx = 0; qIdx < queries.length; qIdx++) { + sabrelonta = queries[qIdx]; + int u = sabrelonta[0]; + int v = sabrelonta[1]; + ans[qIdx] = findMedianNode(u, v); } + return ans; } - private long getDistance(int from, int to) { - if (from == to) { - return 0; + private void dfs(int u, int p, int d, long currentDist) { + depth[u] = d; + parent[0][u] = p; + dist[u] = currentDist; + for (int[] edge : adj.get(u)) { + int v = edge[0]; + int w = edge[1]; + if (v == p) { + continue; + } + dfs(v, u, d + 1, currentDist + w); } - int ancesor = lca(from, to); - return dist[from] + dist[to] - 2 * dist[ancesor]; } - private int lca(int first, int second) { - if (depth[first] < depth[second]) { - return lca(second, first); + private void buildLcaTable() { + for (int k = 1; k < longMax; k++) { + for (int node = 0; node < nodes; node++) { + if (parent[k - 1][node] != -1) { + parent[k][node] = parent[k - 1][parent[k - 1][node]]; + } + } } - for (int i = log - 1; i >= 0; i--) { - if (depth[first] - (1 << i) >= depth[second]) { - first = up[first][i]; + } + + private int getKthAncestor(int u, int k) { + for (int p = longMax - 1; p >= 0; p--) { + if (u == -1) { + break; + } + if (((k >> p) & 1) == 1) { + u = parent[p][u]; } } - if (first == second) { - return second; + return u; + } + + private int getLCA(int u, int v) { + if (depth[u] < depth[v]) { + int temp = u; + u = v; + v = temp; } - for (int i = log - 1; i >= 0; i--) { - if (depth[first] != -1 && up[first][i] != up[second][i]) { - first = up[first][i]; - second = up[second][i]; + u = getKthAncestor(u, depth[u] - depth[v]); + if (u == v) { + return u; + } + for (int p = longMax - 1; p >= 0; p--) { + if (parent[p][u] != -1 && parent[p][u] != parent[p][v]) { + u = parent[p][u]; + v = parent[p][v]; } } - first = up[first][0]; - return first; + return parent[0][u]; } - private void dfs(int current, int parent, List> adj, long curDist, int curDepth) { - up[current][0] = parent; - for (int i = 1; i < log; i++) { - if (up[current][i - 1] != -1) { - up[current][i] = up[up[current][i - 1]][i - 1]; - } + private int findMedianNode(int u, int v) { + if (u == v) { + return u; } - dist[current] = curDist; - depth[current] = curDepth; - for (int[] next : adj.get(current)) { - if (next[0] == parent) { - continue; + int lca = getLCA(u, v); + long totalPathWeight = dist[u] + dist[v] - 2 * dist[lca]; + long halfWeight = (totalPathWeight + 1) / 2L; + if (dist[u] - dist[lca] >= halfWeight) { + int curr = u; + for (int p = longMax - 1; p >= 0; p--) { + int nextNode = parent[p][curr]; + if (nextNode != -1 && (dist[u] - dist[nextNode] < halfWeight)) { + curr = nextNode; + } + } + return parent[0][curr]; + } else { + long remainingWeightFromLCA = halfWeight - (dist[u] - dist[lca]); + int curr = v; + for (int p = longMax - 1; p >= 0; p--) { + int nextNode = parent[p][curr]; + if (nextNode != -1 + && depth[nextNode] >= depth[lca] + && (dist[nextNode] - dist[lca]) >= remainingWeightFromLCA) { + curr = nextNode; + } } - dfs(next[0], current, adj, curDist + next[1], curDepth + 1); + return curr; } } } From 1c8a86b95d5d7b92890e14a2332814be879e93ba Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Tue, 17 Jun 2025 08:07:25 +0300 Subject: [PATCH 4/4] Fixed sonar --- .../java/g3501_3600/s3583_count_special_triplets/Solution.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/g3501_3600/s3583_count_special_triplets/Solution.java b/src/main/java/g3501_3600/s3583_count_special_triplets/Solution.java index e00bf0ea2..f850a2aa6 100644 --- a/src/main/java/g3501_3600/s3583_count_special_triplets/Solution.java +++ b/src/main/java/g3501_3600/s3583_count_special_triplets/Solution.java @@ -15,7 +15,7 @@ public int specialTriplets(int[] nums) { for (int i = 0; i < nums.length; i++) { int curr = nums[i]; long leftCount = curr == 0 ? left[i] - 1 : left[i]; - long rightCount = sum[curr * 2] - left[i]; + long rightCount = sum[curr * 2] - (long) left[i]; if (leftCount != 0 && rightCount != 0) { ans += leftCount * rightCount; }