diff --git a/src/main/java/g3701_3800/s3777_minimum_deletions_to_make_alternating_substring/Solution.java b/src/main/java/g3701_3800/s3777_minimum_deletions_to_make_alternating_substring/Solution.java new file mode 100644 index 000000000..f09e8619d --- /dev/null +++ b/src/main/java/g3701_3800/s3777_minimum_deletions_to_make_alternating_substring/Solution.java @@ -0,0 +1,61 @@ +package g3701_3800.s3777_minimum_deletions_to_make_alternating_substring; + +// #Hard #String #Segment_Tree #Senior_Staff #Weekly_Contest_480 +// #2026_05_06_Time_35_ms_(100.00%)_Space_247.99_MB_(90.00%) + +import java.util.Arrays; + +public class Solution { + private int[] f; + private int n; + + private void add(int i, int v) { + for (i++; i <= n; i += i & -i) { + f[i] += v; + } + } + + private int sum(int i) { + int s = 0; + for (i++; i > 0; i -= i & -i) { + s += f[i]; + } + return s; + } + + public int[] minDeletions(String s, int[][] q) { + char[] a = s.toCharArray(); + n = a.length; + f = new int[n + 1]; + for (int i = 0; i + 1 < n; i++) { + if (a[i] == a[i + 1]) { + add(i, 1); + } + } + int[] ans = new int[q.length]; + int k = 0; + for (int[] e : q) { + if (e[0] == 1) { + int j = e[1]; + if (j > 0 && a[j] == a[j - 1]) { + add(j - 1, -1); + } + if (j + 1 < n && a[j] == a[j + 1]) { + add(j, -1); + } + a[j] = a[j] == 'A' ? 'B' : 'A'; + if (j > 0 && a[j] == a[j - 1]) { + add(j - 1, 1); + } + if (j + 1 < n && a[j] == a[j + 1]) { + add(j, 1); + } + } else { + int l = e[1]; + int r = e[2]; + ans[k++] = l < r ? sum(r - 1) - sum(l - 1) : 0; + } + } + return Arrays.copyOf(ans, k); + } +} diff --git a/src/main/java/g3701_3800/s3777_minimum_deletions_to_make_alternating_substring/readme.md b/src/main/java/g3701_3800/s3777_minimum_deletions_to_make_alternating_substring/readme.md new file mode 100644 index 000000000..d2790092d --- /dev/null +++ b/src/main/java/g3701_3800/s3777_minimum_deletions_to_make_alternating_substring/readme.md @@ -0,0 +1,73 @@ +3777\. Minimum Deletions to Make Alternating Substring + +Hard + +You are given a string `s` of length `n` consisting only of the characters `'A'` and `'B'`. + +You are also given a 2D integer array `queries` of length `q`, where each `queries[i]` is one of the following: + +* `[1, j]`: **Flip** the character at index `j` of `s` i.e. `'A'` changes to `'B'` (and vice versa). This operation mutates `s` and affects subsequent queries. +* `[2, l, r]`: **Compute** the **minimum** number of character deletions required to make the **substring** `s[l..r]` **alternating**. This operation does not modify `s`; the length of `s` remains `n`. + +A **substring** is **alternating** if no two **adjacent** characters are **equal**. A substring of length 1 is always alternating. + +Return an integer array `answer`, where `answer[i]` is the result of the ith query of type `[2, l, r]`. + +**Example 1:** + +**Input:** s = "ABA", queries = [[2,1,2],[1,1],[2,0,2]] + +**Output:** [0,2] + +**Explanation:** + +| i | queries[i] | j | l | r | s before query | s[l..r] | Result | Answer | +|---|------------|---|---|---|----------------|---------|--------|--------| +| 0 | [2, 1, 2] | - | 1 | 2 | `"ABA"` | `"BA"` | Already alternating | 0 | +| 1 | [1, 1] | 1 | - | - | `"ABA"` | - | Flip `s[1]` from `'B'` to `'A'` | - | +| 2 | [2, 0, 2] | - | 0 | 2 | `"AAA"` | `"AAA"` | Delete any two `'A'`s to get `"A"` | 2 | + +Thus, the answer is `[0, 2]`. + +**Example 2:** + +**Input:** s = "ABB", queries = [[2,0,2],[1,2],[2,0,2]] + +**Output:** [1,0] + +**Explanation:** + +| i | queries[i] | j | l | r | s before query | s[l..r] | Result | Answer | +|---|------------|---|---|---|----------------|---------|--------|--------| +| 0 | [2, 0, 2] | - | 0 | 2 | `"ABB"` | `"ABB"` | Delete one `'B'` to get `"AB"` | 1 | +| 1 | [1, 2] | 2 | - | - | `"ABB"` | - | Flip `s[2]` from `'B'` to `'A'` | - | +| 2 | [2, 0, 2] | - | 0 | 2 | `"ABA"` | `"ABA"` | Already alternating | 0 | + +Thus, the answer is `[1, 0]`. + +**Example 3:** + +**Input:** s = "BABA", queries = [[2,0,3],[1,1],[2,1,3]] + +**Output:** [0,1] + +**Explanation:** + +| i | queries[i] | j | l | r | s before query | s[l..r] | Result | Answer | +|---|------------|---|---|---|----------------|---------|--------|--------| +| 0 | [2, 0, 3] | - | 0 | 3 | `"BABA"` | `"BABA"`| Already alternating | 0 | +| 1 | [1, 1] | 1 | - | - | `"BABA"` | - | Flip `s[1]` from `'A'` to `'B'` | - | +| 2 | [2, 1, 3] | - | 1 | 3 | `"BBBA"` | `"BBA"` | Delete one `'B'` to get `"BA"` | 1 | + +Thus, the answer is `[0, 1]`. + +**Constraints:** + +* 1 <= n == s.length <= 105 +* `s[i]` is either `'A'` or `'B'`. +* 1 <= q == queries.length <= 105 +* `queries[i].length == 2` or `3` + * `queries[i] == [1, j]` or, + * `queries[i] == [2, l, r]` + * `0 <= j <= n - 1` + * `0 <= l <= r <= n - 1` \ No newline at end of file diff --git a/src/test/java/g3701_3800/s3777_minimum_deletions_to_make_alternating_substring/SolutionTest.java b/src/test/java/g3701_3800/s3777_minimum_deletions_to_make_alternating_substring/SolutionTest.java new file mode 100644 index 000000000..7c01f6150 --- /dev/null +++ b/src/test/java/g3701_3800/s3777_minimum_deletions_to_make_alternating_substring/SolutionTest.java @@ -0,0 +1,108 @@ +package g3701_3800.s3777_minimum_deletions_to_make_alternating_substring; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.Test; + +class SolutionTest { + @Test + void minDeletions() { + assertThat( + new Solution().minDeletions("ABA", new int[][] {{2, 1, 2}, {1, 1}, {2, 0, 2}}), + equalTo(new int[] {0, 2})); + } + + @Test + void minDeletions2() { + assertThat( + new Solution().minDeletions("ABB", new int[][] {{2, 0, 2}, {1, 2}, {2, 0, 2}}), + equalTo(new int[] {1, 0})); + } + + @Test + void minDeletions3() { + assertThat( + new Solution().minDeletions("BABA", new int[][] {{2, 0, 3}, {1, 1}, {2, 1, 3}}), + equalTo(new int[] {0, 1})); + } + + @Test + void minDeletions4() { + // j == 0, tests j > 0 false branch + // "AAB" -> flip index 0 -> "BAB" + assertThat( + new Solution().minDeletions("AAB", new int[][] {{2, 0, 2}, {1, 0}, {2, 0, 2}}), + equalTo(new int[] {1, 0})); + } + + @Test + void minDeletions5() { + // j == n-1, tests j + 1 < n false branch + // "ABB" -> flip index 2 -> "ABA" + assertThat( + new Solution().minDeletions("ABB", new int[][] {{2, 0, 2}, {1, 2}, {2, 0, 2}}), + equalTo(new int[] {1, 0})); + } + + @Test + void minDeletions6() { + // tests a[j] == 'A' false branch (i.e., 'B' -> 'A') + // "BAA" -> flip index 0 (B) -> "AAA" + assertThat( + new Solution().minDeletions("BAA", new int[][] {{2, 0, 2}, {1, 0}, {2, 0, 2}}), + equalTo(new int[] {1, 2})); + } + + @Test + void minDeletions7() { + // tests a[j] == 'A' true branch + // "AAA" -> flip index 1 -> "ABA" + assertThat( + new Solution().minDeletions("AAA", new int[][] {{2, 0, 2}, {1, 1}, {2, 0, 2}}), + equalTo(new int[] {2, 0})); + } + + @Test + void minDeletions8() { + // tests l < r false branch + assertThat( + new Solution().minDeletions("AAB", new int[][] {{2, 1, 1}, {2, 0, 0}}), + equalTo(new int[] {0, 0})); + } + + @Test + void minDeletions9() { + // larger string to exercise BIT loops more + // "AABBA" -> pairs at index 0 (AA), 2 (BB) + assertThat( + new Solution() + .minDeletions( + "AABBA", + new int[][] { + {2, 0, 4}, {1, 2}, {2, 0, 4}, {1, 0}, {2, 0, 4}, {2, 1, 3} + }), + equalTo(new int[] {2, 2, 1, 1})); + } + + @Test + void minDeletions10() { + // All neighbor pairs match + // "AAAA" -> flip middle to break/create pairs + assertThat( + new Solution() + .minDeletions( + "AAAA", new int[][] {{2, 0, 3}, {1, 2}, {2, 0, 3}, {2, 0, 1}}), + equalTo(new int[] {3, 1, 1})); + } + + @Test + void minDeletions11() { + // No initial neighbor pairs - covers a[i] == a[i+1] false branch dominantly + assertThat( + new Solution() + .minDeletions( + "ABABAB", new int[][] {{2, 0, 5}, {1, 3}, {2, 0, 5}, {2, 2, 4}}), + equalTo(new int[] {0, 2, 2})); + } +}