From 33b5b9f24cec36becc3224132a108ffd671271ca Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Tue, 22 Oct 2024 13:54:13 +0300 Subject: [PATCH 1/2] Added tasks 3324-3327 --- .../Solution.kt | 23 ++++++ .../readme.md | 42 +++++++++++ .../Solution.kt | 23 ++++++ .../readme.md | 36 +++++++++ .../Solution.kt | 51 +++++++++++++ .../readme.md | 40 ++++++++++ .../Solution.kt | 75 +++++++++++++++++++ .../readme.md | 61 +++++++++++++++ .../SolutionTest.kt | 28 +++++++ .../SolutionTest.kt | 17 +++++ .../SolutionTest.kt | 22 ++++++ .../SolutionTest.kt | 23 ++++++ 12 files changed, 441 insertions(+) create mode 100644 src/main/kotlin/g3301_3400/s3324_find_the_sequence_of_strings_appeared_on_the_screen/Solution.kt create mode 100644 src/main/kotlin/g3301_3400/s3324_find_the_sequence_of_strings_appeared_on_the_screen/readme.md create mode 100644 src/main/kotlin/g3301_3400/s3325_count_substrings_with_k_frequency_characters_i/Solution.kt create mode 100644 src/main/kotlin/g3301_3400/s3325_count_substrings_with_k_frequency_characters_i/readme.md create mode 100644 src/main/kotlin/g3301_3400/s3326_minimum_division_operations_to_make_array_non_decreasing/Solution.kt create mode 100644 src/main/kotlin/g3301_3400/s3326_minimum_division_operations_to_make_array_non_decreasing/readme.md create mode 100644 src/main/kotlin/g3301_3400/s3327_check_if_dfs_strings_are_palindromes/Solution.kt create mode 100644 src/main/kotlin/g3301_3400/s3327_check_if_dfs_strings_are_palindromes/readme.md create mode 100644 src/test/kotlin/g3301_3400/s3324_find_the_sequence_of_strings_appeared_on_the_screen/SolutionTest.kt create mode 100644 src/test/kotlin/g3301_3400/s3325_count_substrings_with_k_frequency_characters_i/SolutionTest.kt create mode 100644 src/test/kotlin/g3301_3400/s3326_minimum_division_operations_to_make_array_non_decreasing/SolutionTest.kt create mode 100644 src/test/kotlin/g3301_3400/s3327_check_if_dfs_strings_are_palindromes/SolutionTest.kt diff --git a/src/main/kotlin/g3301_3400/s3324_find_the_sequence_of_strings_appeared_on_the_screen/Solution.kt b/src/main/kotlin/g3301_3400/s3324_find_the_sequence_of_strings_appeared_on_the_screen/Solution.kt new file mode 100644 index 000000000..3da714d16 --- /dev/null +++ b/src/main/kotlin/g3301_3400/s3324_find_the_sequence_of_strings_appeared_on_the_screen/Solution.kt @@ -0,0 +1,23 @@ +package g3301_3400.s3324_find_the_sequence_of_strings_appeared_on_the_screen + +// #Medium #String #Simulation #2024_10_22_Time_8_ms_(100.00%)_Space_62.7_MB_(29.63%) + +class Solution { + fun stringSequence(target: String): List { + val ans: MutableList = ArrayList() + val l = target.length + val cur = StringBuilder() + for (i in 0 until l) { + val tCh = target[i] + cur.append('a') + ans.add(cur.toString()) + while (cur.get(i) != tCh) { + val lastCh = cur.get(i) + val nextCh = (if (lastCh == 'z') 'a'.code else lastCh.code + 1).toChar() + cur.setCharAt(i, nextCh) + ans.add(cur.toString()) + } + } + return ans + } +} diff --git a/src/main/kotlin/g3301_3400/s3324_find_the_sequence_of_strings_appeared_on_the_screen/readme.md b/src/main/kotlin/g3301_3400/s3324_find_the_sequence_of_strings_appeared_on_the_screen/readme.md new file mode 100644 index 000000000..40579fd0e --- /dev/null +++ b/src/main/kotlin/g3301_3400/s3324_find_the_sequence_of_strings_appeared_on_the_screen/readme.md @@ -0,0 +1,42 @@ +3324\. Find the Sequence of Strings Appeared on the Screen + +Medium + +You are given a string `target`. + +Alice is going to type `target` on her computer using a special keyboard that has **only two** keys: + +* Key 1 appends the character `"a"` to the string on the screen. +* Key 2 changes the **last** character of the string on the screen to its **next** character in the English alphabet. For example, `"c"` changes to `"d"` and `"z"` changes to `"a"`. + +**Note** that initially there is an _empty_ string `""` on the screen, so she can **only** press key 1. + +Return a list of _all_ strings that appear on the screen as Alice types `target`, in the order they appear, using the **minimum** key presses. + +**Example 1:** + +**Input:** target = "abc" + +**Output:** ["a","aa","ab","aba","abb","abc"] + +**Explanation:** + +The sequence of key presses done by Alice are: + +* Press key 1, and the string on the screen becomes `"a"`. +* Press key 1, and the string on the screen becomes `"aa"`. +* Press key 2, and the string on the screen becomes `"ab"`. +* Press key 1, and the string on the screen becomes `"aba"`. +* Press key 2, and the string on the screen becomes `"abb"`. +* Press key 2, and the string on the screen becomes `"abc"`. + +**Example 2:** + +**Input:** target = "he" + +**Output:** ["a","b","c","d","e","f","g","h","ha","hb","hc","hd","he"] + +**Constraints:** + +* `1 <= target.length <= 400` +* `target` consists only of lowercase English letters. \ No newline at end of file diff --git a/src/main/kotlin/g3301_3400/s3325_count_substrings_with_k_frequency_characters_i/Solution.kt b/src/main/kotlin/g3301_3400/s3325_count_substrings_with_k_frequency_characters_i/Solution.kt new file mode 100644 index 000000000..576ec94f9 --- /dev/null +++ b/src/main/kotlin/g3301_3400/s3325_count_substrings_with_k_frequency_characters_i/Solution.kt @@ -0,0 +1,23 @@ +package g3301_3400.s3325_count_substrings_with_k_frequency_characters_i + +// #Medium #String #Hash_Table #Sliding_Window #2024_10_22_Time_3_ms_(88.00%)_Space_35.9_MB_(76.00%) + +class Solution { + fun numberOfSubstrings(s: String, k: Int): Int { + var left = 0 + var result = 0 + val count = IntArray(26) + for (i in 0 until s.length) { + val ch = s.get(i) + count[ch.code - 'a'.code]++ + + while (count[ch.code - 'a'.code] == k) { + result += s.length - i + val atLeft = s.get(left) + count[atLeft.code - 'a'.code]-- + left++ + } + } + return result + } +} diff --git a/src/main/kotlin/g3301_3400/s3325_count_substrings_with_k_frequency_characters_i/readme.md b/src/main/kotlin/g3301_3400/s3325_count_substrings_with_k_frequency_characters_i/readme.md new file mode 100644 index 000000000..d13f50198 --- /dev/null +++ b/src/main/kotlin/g3301_3400/s3325_count_substrings_with_k_frequency_characters_i/readme.md @@ -0,0 +1,36 @@ +3325\. Count Substrings With K-Frequency Characters I + +Medium + +Given a string `s` and an integer `k`, return the total number of substrings of `s` where **at least one** character appears **at least** `k` times. + +**Example 1:** + +**Input:** s = "abacb", k = 2 + +**Output:** 4 + +**Explanation:** + +The valid substrings are: + +* `"aba"` (character `'a'` appears 2 times). +* `"abac"` (character `'a'` appears 2 times). +* `"abacb"` (character `'a'` appears 2 times). +* `"bacb"` (character `'b'` appears 2 times). + +**Example 2:** + +**Input:** s = "abcde", k = 1 + +**Output:** 15 + +**Explanation:** + +All substrings are valid because every character appears at least once. + +**Constraints:** + +* `1 <= s.length <= 3000` +* `1 <= k <= s.length` +* `s` consists only of lowercase English letters. \ No newline at end of file diff --git a/src/main/kotlin/g3301_3400/s3326_minimum_division_operations_to_make_array_non_decreasing/Solution.kt b/src/main/kotlin/g3301_3400/s3326_minimum_division_operations_to_make_array_non_decreasing/Solution.kt new file mode 100644 index 000000000..58d198103 --- /dev/null +++ b/src/main/kotlin/g3301_3400/s3326_minimum_division_operations_to_make_array_non_decreasing/Solution.kt @@ -0,0 +1,51 @@ +package g3301_3400.s3326_minimum_division_operations_to_make_array_non_decreasing + +// #Medium #Array #Math #Greedy #Number_Theory +// #2024_10_22_Time_24_ms_(94.12%)_Space_64.2_MB_(64.71%) + +import kotlin.math.max + +class Solution { + fun minOperations(nums: IntArray): Int { + compute() + var op = 0 + val n = nums.size + for (i in n - 2 downTo 0) { + while (nums[i] > nums[i + 1]) { + if (SIEVE[nums[i]] == 0) { + return -1 + } + nums[i] /= SIEVE[nums[i]] + op++ + } + if (nums[i] > nums[i + 1]) { + return -1 + } + } + return op + } + + companion object { + private const val MAXI = 1000001 + private val SIEVE = IntArray(MAXI) + private var precompute = false + + private fun compute() { + if (precompute) { + return + } + for (i in 2 until MAXI) { + if (i * i > MAXI) { + break + } + var j = i * i + while (j < MAXI) { + SIEVE[j] = + max(SIEVE[j], max(i, (j / i))) + j += i + } + } + precompute = true + } + } +} diff --git a/src/main/kotlin/g3301_3400/s3326_minimum_division_operations_to_make_array_non_decreasing/readme.md b/src/main/kotlin/g3301_3400/s3326_minimum_division_operations_to_make_array_non_decreasing/readme.md new file mode 100644 index 000000000..a43b41a5a --- /dev/null +++ b/src/main/kotlin/g3301_3400/s3326_minimum_division_operations_to_make_array_non_decreasing/readme.md @@ -0,0 +1,40 @@ +3326\. Minimum Division Operations to Make Array Non Decreasing + +Medium + +You are given an integer array `nums`. + +Any **positive** divisor of a natural number `x` that is **strictly less** than `x` is called a **proper divisor** of `x`. For example, 2 is a _proper divisor_ of 4, while 6 is not a _proper divisor_ of 6. + +You are allowed to perform an **operation** any number of times on `nums`, where in each **operation** you select any _one_ element from `nums` and divide it by its **greatest** **proper divisor**. + +Return the **minimum** number of **operations** required to make the array **non-decreasing**. + +If it is **not** possible to make the array _non-decreasing_ using any number of operations, return `-1`. + +**Example 1:** + +**Input:** nums = [25,7] + +**Output:** 1 + +**Explanation:** + +Using a single operation, 25 gets divided by 5 and `nums` becomes `[5, 7]`. + +**Example 2:** + +**Input:** nums = [7,7,6] + +**Output:** \-1 + +**Example 3:** + +**Input:** nums = [1,1,1,1] + +**Output:** 0 + +**Constraints:** + +* 1 <= nums.length <= 105 +* 1 <= nums[i] <= 106 \ No newline at end of file diff --git a/src/main/kotlin/g3301_3400/s3327_check_if_dfs_strings_are_palindromes/Solution.kt b/src/main/kotlin/g3301_3400/s3327_check_if_dfs_strings_are_palindromes/Solution.kt new file mode 100644 index 000000000..23c1fb123 --- /dev/null +++ b/src/main/kotlin/g3301_3400/s3327_check_if_dfs_strings_are_palindromes/Solution.kt @@ -0,0 +1,75 @@ +package g3301_3400.s3327_check_if_dfs_strings_are_palindromes + +// #Hard #Array #String #Hash_Table #Depth_First_Search #Tree #Hash_Function +// #2024_10_22_Time_165_ms_(100.00%)_Space_88.9_MB_(66.67%) + +import kotlin.math.min + +class Solution { + private val e: MutableList?> = ArrayList?>() + private val stringBuilder = StringBuilder() + private var s: String? = null + private var now = 0 + private var n = 0 + private lateinit var l: IntArray + private lateinit var r: IntArray + private lateinit var p: IntArray + private lateinit var c: CharArray + + private fun dfs(x: Int) { + l[x] = now + 1 + for (v in e.get(x)!!) { + dfs(v!!) + } + stringBuilder.append(s!!.get(x)) + r[x] = ++now + } + + private fun matcher() { + c[0] = '~' + c[1] = '#' + for (i in 1..n) { + c[2 * i + 1] = '#' + c[2 * i] = stringBuilder.get(i - 1) + } + var j = 1 + var mid = 0 + var localR = 0 + while (j <= 2 * n + 1) { + if (j <= localR) { + p[j] = min(p[(mid shl 1) - j], (localR - j + 1)) + } + while (c[j - p[j]] == c[j + p[j]]) { + ++p[j] + } + if (p[j] + j > localR) { + localR = p[j] + j - 1 + mid = j + } + ++j + } + } + + fun findAnswer(parent: IntArray, s: String): BooleanArray { + n = parent.size + this.s = s + for (i in 0 until n) { + e.add(ArrayList()) + } + for (i in 1 until n) { + e.get(parent[i])!!.add(i) + } + l = IntArray(n) + r = IntArray(n) + dfs(0) + c = CharArray(2 * n + 10) + p = IntArray(2 * n + 10) + matcher() + val ans = BooleanArray(n) + for (i in 0 until n) { + val mid = (2 * r[i] - 2 * l[i] + 1) / 2 + 2 * l[i] + ans[i] = p[mid] - 1 >= r[i] - l[i] + 1 + } + return ans + } +} diff --git a/src/main/kotlin/g3301_3400/s3327_check_if_dfs_strings_are_palindromes/readme.md b/src/main/kotlin/g3301_3400/s3327_check_if_dfs_strings_are_palindromes/readme.md new file mode 100644 index 000000000..789a9c56b --- /dev/null +++ b/src/main/kotlin/g3301_3400/s3327_check_if_dfs_strings_are_palindromes/readme.md @@ -0,0 +1,61 @@ +3327\. Check if DFS Strings Are Palindromes + +Hard + +You are given a tree rooted at node 0, consisting of `n` nodes numbered from `0` to `n - 1`. The tree is represented by an array `parent` of size `n`, where `parent[i]` is the parent of node `i`. Since node 0 is the root, `parent[0] == -1`. + +You are also given a string `s` of length `n`, where `s[i]` is the character assigned to node `i`. + +Consider an empty string `dfsStr`, and define a recursive function `dfs(int x)` that takes a node `x` as a parameter and performs the following steps in order: + +* Iterate over each child `y` of `x` **in increasing order of their numbers**, and call `dfs(y)`. +* Add the character `s[x]` to the end of the string `dfsStr`. + +**Note** that `dfsStr` is shared across all recursive calls of `dfs`. + +You need to find a boolean array `answer` of size `n`, where for each index `i` from `0` to `n - 1`, you do the following: + +* Empty the string `dfsStr` and call `dfs(i)`. +* If the resulting string `dfsStr` is a **palindrome**, then set `answer[i]` to `true`. Otherwise, set `answer[i]` to `false`. + +Return the array `answer`. + +A **palindrome** is a string that reads the same forward and backward. + +**Example 1:** + +![](https://assets.leetcode.com/uploads/2024/09/01/tree1drawio.png) + +**Input:** parent = [-1,0,0,1,1,2], s = "aababa" + +**Output:** [true,true,false,true,true,true] + +**Explanation:** + +* Calling `dfs(0)` results in the string `dfsStr = "abaaba"`, which is a palindrome. +* Calling `dfs(1)` results in the string `dfsStr = "aba"`, which is a palindrome. +* Calling `dfs(2)` results in the string `dfsStr = "ab"`, which is **not** a palindrome. +* Calling `dfs(3)` results in the string `dfsStr = "a"`, which is a palindrome. +* Calling `dfs(4)` results in the string `dfsStr = "b"`, which is a palindrome. +* Calling `dfs(5)` results in the string `dfsStr = "a"`, which is a palindrome. + +**Example 2:** + +![](https://assets.leetcode.com/uploads/2024/09/01/tree2drawio-1.png) + +**Input:** parent = [-1,0,0,0,0], s = "aabcb" + +**Output:** [true,true,true,true,true] + +**Explanation:** + +Every call on `dfs(x)` results in a palindrome string. + +**Constraints:** + +* `n == parent.length == s.length` +* 1 <= n <= 105 +* `0 <= parent[i] <= n - 1` for all `i >= 1`. +* `parent[0] == -1` +* `parent` represents a valid tree. +* `s` consists only of lowercase English letters. \ No newline at end of file diff --git a/src/test/kotlin/g3301_3400/s3324_find_the_sequence_of_strings_appeared_on_the_screen/SolutionTest.kt b/src/test/kotlin/g3301_3400/s3324_find_the_sequence_of_strings_appeared_on_the_screen/SolutionTest.kt new file mode 100644 index 000000000..6c00aefdc --- /dev/null +++ b/src/test/kotlin/g3301_3400/s3324_find_the_sequence_of_strings_appeared_on_the_screen/SolutionTest.kt @@ -0,0 +1,28 @@ +package g3301_3400.s3324_find_the_sequence_of_strings_appeared_on_the_screen + +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Test + +internal class SolutionTest { + @Test + fun stringSequence() { + assertThat>( + Solution().stringSequence("abc"), + equalTo>(listOf("a", "aa", "ab", "aba", "abb", "abc")) + ) + } + + @Test + fun stringSequence2() { + assertThat>( + Solution().stringSequence("he"), + equalTo>( + listOf( + "a", "b", "c", "d", "e", "f", "g", "h", "ha", "hb", "hc", "hd", + "he" + ) + ) + ) + } +} diff --git a/src/test/kotlin/g3301_3400/s3325_count_substrings_with_k_frequency_characters_i/SolutionTest.kt b/src/test/kotlin/g3301_3400/s3325_count_substrings_with_k_frequency_characters_i/SolutionTest.kt new file mode 100644 index 000000000..84b15366e --- /dev/null +++ b/src/test/kotlin/g3301_3400/s3325_count_substrings_with_k_frequency_characters_i/SolutionTest.kt @@ -0,0 +1,17 @@ +package g3301_3400.s3325_count_substrings_with_k_frequency_characters_i + +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Test + +internal class SolutionTest { + @Test + fun numberOfSubstrings() { + assertThat(Solution().numberOfSubstrings("abacb", 2), equalTo(4)) + } + + @Test + fun numberOfSubstrings2() { + assertThat(Solution().numberOfSubstrings("abcde", 1), equalTo(15)) + } +} diff --git a/src/test/kotlin/g3301_3400/s3326_minimum_division_operations_to_make_array_non_decreasing/SolutionTest.kt b/src/test/kotlin/g3301_3400/s3326_minimum_division_operations_to_make_array_non_decreasing/SolutionTest.kt new file mode 100644 index 000000000..0810b311c --- /dev/null +++ b/src/test/kotlin/g3301_3400/s3326_minimum_division_operations_to_make_array_non_decreasing/SolutionTest.kt @@ -0,0 +1,22 @@ +package g3301_3400.s3326_minimum_division_operations_to_make_array_non_decreasing + +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Test + +internal class SolutionTest { + @Test + fun minOperations() { + assertThat(Solution().minOperations(intArrayOf(25, 7)), equalTo(1)) + } + + @Test + fun minOperations2() { + assertThat(Solution().minOperations(intArrayOf(7, 7, 6)), equalTo(-1)) + } + + @Test + fun minOperations3() { + assertThat(Solution().minOperations(intArrayOf(1, 1, 1, 1)), equalTo(0)) + } +} diff --git a/src/test/kotlin/g3301_3400/s3327_check_if_dfs_strings_are_palindromes/SolutionTest.kt b/src/test/kotlin/g3301_3400/s3327_check_if_dfs_strings_are_palindromes/SolutionTest.kt new file mode 100644 index 000000000..61fb2dd0b --- /dev/null +++ b/src/test/kotlin/g3301_3400/s3327_check_if_dfs_strings_are_palindromes/SolutionTest.kt @@ -0,0 +1,23 @@ +package g3301_3400.s3327_check_if_dfs_strings_are_palindromes + +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.junit.jupiter.api.Test + +internal class SolutionTest { + @Test + fun findAnswer() { + assertThat( + Solution().findAnswer(intArrayOf(-1, 0, 0, 1, 1, 2), "aababa"), + equalTo(booleanArrayOf(true, true, false, true, true, true)) + ) + } + + @Test + fun findAnswer2() { + assertThat( + Solution().findAnswer(intArrayOf(-1, 0, 0, 0, 0), "aabcb"), + equalTo(booleanArrayOf(true, true, true, true, true)) + ) + } +} From dcae13ab0eaac0cd8b5fcaee11d537a052c4b538 Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Tue, 22 Oct 2024 14:02:04 +0300 Subject: [PATCH 2/2] Fixed sonar --- .../Solution.kt | 4 ++-- .../Solution.kt | 4 ++-- .../Solution.kt | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/g3301_3400/s3324_find_the_sequence_of_strings_appeared_on_the_screen/Solution.kt b/src/main/kotlin/g3301_3400/s3324_find_the_sequence_of_strings_appeared_on_the_screen/Solution.kt index 3da714d16..216ce9017 100644 --- a/src/main/kotlin/g3301_3400/s3324_find_the_sequence_of_strings_appeared_on_the_screen/Solution.kt +++ b/src/main/kotlin/g3301_3400/s3324_find_the_sequence_of_strings_appeared_on_the_screen/Solution.kt @@ -11,8 +11,8 @@ class Solution { val tCh = target[i] cur.append('a') ans.add(cur.toString()) - while (cur.get(i) != tCh) { - val lastCh = cur.get(i) + while (cur[i] != tCh) { + val lastCh = cur[i] val nextCh = (if (lastCh == 'z') 'a'.code else lastCh.code + 1).toChar() cur.setCharAt(i, nextCh) ans.add(cur.toString()) diff --git a/src/main/kotlin/g3301_3400/s3325_count_substrings_with_k_frequency_characters_i/Solution.kt b/src/main/kotlin/g3301_3400/s3325_count_substrings_with_k_frequency_characters_i/Solution.kt index 576ec94f9..14283dec6 100644 --- a/src/main/kotlin/g3301_3400/s3325_count_substrings_with_k_frequency_characters_i/Solution.kt +++ b/src/main/kotlin/g3301_3400/s3325_count_substrings_with_k_frequency_characters_i/Solution.kt @@ -8,12 +8,12 @@ class Solution { var result = 0 val count = IntArray(26) for (i in 0 until s.length) { - val ch = s.get(i) + val ch = s[i] count[ch.code - 'a'.code]++ while (count[ch.code - 'a'.code] == k) { result += s.length - i - val atLeft = s.get(left) + val atLeft = s[left] count[atLeft.code - 'a'.code]-- left++ } diff --git a/src/main/kotlin/g3301_3400/s3327_check_if_dfs_strings_are_palindromes/Solution.kt b/src/main/kotlin/g3301_3400/s3327_check_if_dfs_strings_are_palindromes/Solution.kt index 23c1fb123..6ba7afdb4 100644 --- a/src/main/kotlin/g3301_3400/s3327_check_if_dfs_strings_are_palindromes/Solution.kt +++ b/src/main/kotlin/g3301_3400/s3327_check_if_dfs_strings_are_palindromes/Solution.kt @@ -18,10 +18,10 @@ class Solution { private fun dfs(x: Int) { l[x] = now + 1 - for (v in e.get(x)!!) { + for (v in e[x]!!) { dfs(v!!) } - stringBuilder.append(s!!.get(x)) + stringBuilder.append(s!![x]) r[x] = ++now } @@ -30,7 +30,7 @@ class Solution { c[1] = '#' for (i in 1..n) { c[2 * i + 1] = '#' - c[2 * i] = stringBuilder.get(i - 1) + c[2 * i] = stringBuilder[i - 1] } var j = 1 var mid = 0 @@ -57,7 +57,7 @@ class Solution { e.add(ArrayList()) } for (i in 1 until n) { - e.get(parent[i])!!.add(i) + e[parent[i]]!!.add(i) } l = IntArray(n) r = IntArray(n)