Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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 <code>i<sup>th</sup></code> 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:**

* <code>1 <= n == s.length <= 10<sup>5</sup></code>
* `s[i]` is either `'A'` or `'B'`.
* <code>1 <= q == queries.length <= 10<sup>5</sup></code>
* `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`
Original file line number Diff line number Diff line change
@@ -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}));
}
}
Loading