3777. Minimum Deletions to Make Alternating Substring
Problem Description
You are given a string s of length n that consists only of the characters 'A' and 'B'.
You are also given a 2D integer array queries of length q. Each queries[i] is one of the following two types:
[1, j]: Flip the character at indexjofs. This means'A'becomes'B'and'B'becomes'A'. This operation changessand therefore affects all subsequent queries.[2, l, r]: Compute the minimum number of character deletions needed to make the substrings[l..r]alternating. This operation does not modifys; the length ofsstaysn.
A substring is alternating if no two adjacent characters are equal. A substring of length 1 is always considered alternating.
Return an integer array answer, where answer[i] is the result of the i-th query of type [2, l, r].
How We Pick the Algorithm
Why Ordered Set / Fenwick / Segment Tree?
This problem maps to Ordered Set / Fenwick / Segment Tree through a short path in the full flowchart.
Flipping characters and querying range sums of adjacent-equal pairs requires a segment tree for efficient updates and queries.
Open in FlowchartIntuition
The key observation is to think about what "deletions to make a substring alternating" really means. A substring is alternating when no two adjacent characters are equal. So whenever we find a pair of adjacent equal characters, we must delete one of them to break that pair. In fact, the minimum number of deletions required is exactly equal to the number of positions where two adjacent characters are equal.
This insight lets us reframe the problem. Instead of looking at the characters directly, we look at the boundaries between adjacent characters. For each index i (with 1 <= i < n), we define a value nums[i] that records whether s[i] equals s[i-1]:
- If
s[i] == s[i-1], thennums[i] = 1(this is a "bad" boundary that needs a deletion). - Otherwise,
nums[i] = 0.
With this transformation, the answer to a query [2, l, r] becomes the sum of nums over the interval [l+1, r]. We start from l+1 because the boundary at index l compares s[l] with s[l-1], which lies outside the substring and should not be counted.
Now consider a flip query [1, j]. Flipping s[j] only changes its relationship with its immediate neighbors. Specifically, it affects the boundary between s[j-1] and s[j] (recorded at nums[j]) and the boundary between s[j] and s[j+1] (recorded at nums[j+1]). Since a flip turns an equal pair into an unequal pair and vice versa, each affected nums value simply toggles between 0 and 1. No other positions are touched.
So we are left with two operations: point updates (toggling at most two nums values per flip) and range sum queries (summing nums over [l+1, r]). This combination of fast updates and fast range sums is exactly what a Binary Indexed Tree (Fenwick Tree) handles efficiently, giving us O(log n) time per operation.
Pattern Learn more about Segment Tree patterns.
Solution Approach
We use a Binary Indexed Tree (Fenwick Tree) to maintain the prefix sum of the nums array, which lets us perform both point updates and range sum queries in O(log n) time.
Step 1: Build the nums array.
We convert the string s into an array nums of length n, where:
nums[0] = 0(there is no character before index0).- For
1 <= i < n,nums[i] = 1ifs[i] == s[i-1], otherwisenums[i] = 0.
Each nums[i] indicates whether there is a pair of adjacent equal characters ending at index i.
Step 2: Initialize the Binary Indexed Tree.
We create a BinaryIndexedTree of size n. While building nums, whenever nums[i] == 1, we call bit.update(i + 1, 1) to add this value to the tree. Note that the tree uses 1-based indexing, so position i in nums maps to position i + 1 in the tree.
The tree supports two core operations:
update(x, delta): addsdeltato positionxand propagates the change upward usingx += x & -x.query(x): returns the prefix sum of the firstxpositions by walking down withx -= x & -x.
Step 3: Process the queries.
We iterate through each query and handle the two types:
-
Flip query
[1, j]: A flip only affects the boundaries atnums[j]andnums[j+1]. For each affected position, we compute the changedelta = (nums[pos] ^ 1) - nums[pos], which is+1if the value goes from0to1and-1if it goes from1to0. We then toggle the value withnums[pos] ^= 1and apply the change to the tree viabit.update. We handlenums[j]directly, and only handlenums[j+1]whenj + 1 < nto stay within bounds. -
Compute query
[2, l, r]: The answer is the sum ofnumsover the interval[l+1, r]. Using prefix sums, this equalsbit.query(r + 1) - bit.query(l + 1). Herebit.query(r + 1)gives the sum ofnums[0..r]andbit.query(l + 1)gives the sum ofnums[0..l], so subtracting leaves the sum overnums[l+1..r], exactly the boundaries inside the substring. We append this result toans.
Step 4: Return the result.
After processing all queries, we return the ans array containing the answers to all [2, l, r] queries in order.
Complexity Analysis:
- Time complexity:
O((n + q) * log n), wherenis the length ofsandqis the number of queries. Building the tree takesO(n log n), and each query is handled inO(log n). - Space complexity:
O(n)for thenumsarray and the Binary Indexed Tree.
Example Walkthrough
Let's trace through a small example to see the solution approach in action.
Input:
s = "ABBA"(son = 4)queries = [[2, 0, 3], [1, 1], [2, 0, 3]]
Step 1: Build the nums array.
We compare each character with its predecessor. Recall nums[i] = 1 when s[i] == s[i-1], else 0. By definition nums[0] = 0.
Index i | s[i] | s[i-1] | Equal? | nums[i] |
|---|---|---|---|---|
| 0 | A | — | — | 0 |
| 1 | B | A | No | 0 |
| 2 | B | B | Yes | 1 |
| 3 | A | B | No | 0 |
So nums = [0, 0, 1, 0]. The single "bad boundary" sits at index 2, where "BB" are adjacent and equal.
Step 2: Initialize the Binary Indexed Tree.
We create a BIT of size 4 (1-based). For every nums[i] == 1, we call bit.update(i + 1, 1).
- Only
nums[2] == 1, so we callbit.update(3, 1).
The BIT now logically holds the array [0, 0, 1, 0] and can answer prefix sums.
Step 3: Process the queries.
Query 1 — [2, 0, 3] (Compute):
We want the minimum deletions to make s[0..3] = "ABBA" alternating. The answer is the sum of nums over [l+1, r] = [1, 3].
answer = bit.query(r + 1) - bit.query(l + 1) = bit.query(4) - bit.query(1) = (nums[0..3] sum) - (nums[0..0] sum) = (0+0+1+0) - (0) = 1
So we need 1 deletion. Intuitively, "ABBA" has one adjacent equal pair ("BB"); deleting one B gives "ABA", which is alternating. ✅ We append 1 to ans.
ans = [1]
Query 2 — [1, 1] (Flip):
We flip s[1] from B to A. The string becomes s = "AABA". A flip at index j = 1 only affects two boundaries: nums[j] = nums[1] and nums[j+1] = nums[2].
Affecting nums[1]:
pos = 1 delta = (nums[1] ^ 1) - nums[1] = (0 ^ 1) - 0 = 1 - 0 = +1 nums[1] ^= 1 -> nums[1] = 1 bit.update(pos + 1, delta) -> bit.update(2, +1)
Now s[0]='A', s[1]='A' are equal, so the new boundary is "bad" — consistent with nums[1] = 1.
Affecting nums[2] (since j+1 = 2 < n):
pos = 2 delta = (nums[2] ^ 1) - nums[2] = (1 ^ 1) - 1 = 0 - 1 = -1 nums[2] ^= 1 -> nums[2] = 0 bit.update(pos + 1, delta) -> bit.update(3, -1)
Now s[1]='A', s[2]='B' are unequal, so that boundary is no longer "bad" — consistent with nums[2] = 0.
After the flip, nums = [0, 1, 0, 0] and the BIT reflects the array [0, 1, 0, 0]. Notice we only touched two positions, never re-scanning the whole string.
Query 3 — [2, 0, 3] (Compute):
Same range as before, but s is now "AABA". The answer is the sum of nums over [1, 3].
answer = bit.query(4) - bit.query(1) = (0+1+0+0) - (0) = 1
So we need 1 deletion again. Checking "AABA": it has one adjacent equal pair ("AA"); deleting one A gives "ABA", which is alternating. ✅ We append 1 to ans.
ans = [1, 1]
Step 4: Return the result.
After all queries, we return:
ans = [1, 1]
Key takeaways from this walkthrough:
- The problem reduces to counting adjacent-equal boundaries inside a range, not the characters themselves.
- A range sum query on
numsanswers each compute query inO(log n). - A flip is a localized event — it toggles at most two
numsvalues, each handled by a singleO(log n)BIT update, so the data structure never falls out of sync with the string.
Solution Implementation
1from typing import List
2
3
4class BinaryIndexedTree:
5 __slots__ = "n", "tree"
6
7 def __init__(self, n: int):
8 # Size of the tree (1-indexed internally)
9 self.n = n
10 # Storage array; index 0 is unused for convenience
11 self.tree = [0] * (n + 1)
12
13 def update(self, x: int, delta: int) -> None:
14 # Add `delta` at position x, propagating upward through parents
15 while x <= self.n:
16 self.tree[x] += delta
17 x += x & -x # move to the next responsible node
18
19 def query(self, x: int) -> int:
20 # Prefix sum of all elements from index 1 to x
21 total = 0
22 while x > 0:
23 total += self.tree[x]
24 x -= x & -x # move to the parent prefix block
25 return total
26
27
28class Solution:
29 def minDeletions(self, s: str, queries: List[List[int]]) -> List[int]:
30 n = len(s)
31 # nums[i] == 1 means s[i] equals s[i-1] (an adjacent duplicate pair)
32 nums = [0] * n
33 bit = BinaryIndexedTree(n)
34
35 # Build the initial Fenwick Tree from adjacent-pair flags
36 for i in range(1, n):
37 nums[i] = int(s[i] == s[i - 1])
38 if nums[i]:
39 # Store flag at 1-indexed position (i + 1)
40 bit.update(i + 1, 1)
41
42 ans: List[int] = []
43 for q in queries:
44 if q[0] == 1:
45 # Type 1: toggle the duplicate-pair flags around index j
46 j = q[1]
47
48 # Toggle nums[j] and reflect the change in the BIT
49 delta = (nums[j] ^ 1) - nums[j]
50 nums[j] ^= 1
51 bit.update(j + 1, delta)
52
53 # The change at j may also affect the pair flag at j + 1
54 if j + 1 < n:
55 delta = (nums[j + 1] ^ 1) - nums[j + 1]
56 nums[j + 1] ^= 1
57 bit.update(j + 2, delta)
58 else:
59 # Type 2: count duplicate pairs within range [l, r]
60 # Equals minimum deletions to remove consecutive duplicates
61 _, l, r = q
62 ans.append(bit.query(r + 1) - bit.query(l + 1))
63
64 return ans
651/**
2 * A Binary Indexed Tree (Fenwick Tree) that supports point updates
3 * and prefix-sum queries in O(log n) time.
4 */
5class BinaryIndexedTree {
6 // Size of the underlying logical array.
7 private int size;
8 // Internal tree storage; indices are 1-based.
9 private int[] tree;
10
11 /**
12 * Constructs a Binary Indexed Tree for an array of the given length.
13 *
14 * @param size the number of elements the tree should support
15 */
16 BinaryIndexedTree(int size) {
17 this.size = size;
18 this.tree = new int[size + 1];
19 }
20
21 /**
22 * Adds {@code delta} to the element at position {@code index} (1-based).
23 *
24 * @param index the 1-based position to update
25 * @param delta the value to add at that position
26 */
27 void update(int index, int delta) {
28 // Walk upward, updating every responsible node by adding the lowbit.
29 while (index <= size) {
30 tree[index] += delta;
31 index += index & -index;
32 }
33 }
34
35 /**
36 * Returns the prefix sum of the first {@code index} elements (1-based).
37 *
38 * @param index the 1-based right boundary (inclusive) of the prefix
39 * @return the sum of elements in the range [1, index]
40 */
41 int query(int index) {
42 int sum = 0;
43 // Walk downward, accumulating partial sums by removing the lowbit.
44 while (index > 0) {
45 sum += tree[index];
46 index -= index & -index;
47 }
48 return sum;
49 }
50}
51
52class Solution {
53 /**
54 * Processes a list of queries over a binary string.
55 *
56 * <p>For each character at position {@code i} (i >= 1), {@code marks[i]} is 1
57 * when {@code s[i] == s[i - 1]} (i.e., this position forms an "equal-adjacent"
58 * pair with its predecessor). The Binary Indexed Tree stores these marks so
59 * that range counts of such pairs can be answered quickly.</p>
60 *
61 * <p>Query types:</p>
62 * <ul>
63 * <li>{@code [1, j]} — toggle character at index {@code j}, refreshing the
64 * affected adjacency marks at positions {@code j} and {@code j + 1}.</li>
65 * <li>{@code [2, l, r]} — count the equal-adjacent pairs within [l, r],
66 * which equals the minimum deletions needed to remove repeats.</li>
67 * </ul>
68 *
69 * @param s the binary string
70 * @param queries the array of queries to process
71 * @return an array of answers, one per type-2 query, in order
72 */
73 public int[] minDeletions(String s, int[][] queries) {
74 int length = s.length();
75 // marks[i] == 1 means s[i] equals s[i - 1]; marks[0] is always 0.
76 int[] marks = new int[length];
77 BinaryIndexedTree bit = new BinaryIndexedTree(length);
78
79 // Initialize the adjacency marks and seed the tree accordingly.
80 for (int i = 1; i < length; i++) {
81 marks[i] = (s.charAt(i) == s.charAt(i - 1)) ? 1 : 0;
82 if (marks[i] == 1) {
83 bit.update(i + 1, 1);
84 }
85 }
86
87 // Pre-count how many type-2 queries exist to size the answer array.
88 int answerCount = 0;
89 for (int[] query : queries) {
90 if (query[0] == 2) {
91 answerCount++;
92 }
93 }
94
95 int[] answers = new int[answerCount];
96 int answerIndex = 0;
97
98 // Note: toggling a character does not change the actual mark values used
99 // in the original logic; the code flips marks and applies the delta so the
100 // tree stays consistent with the maintained marks array.
101 for (int[] query : queries) {
102 if (query[0] == 1) {
103 int position = query[1];
104
105 // Flip the mark at this position and reflect the change in the tree.
106 int delta = (marks[position] ^ 1) - marks[position];
107 marks[position] ^= 1;
108 bit.update(position + 1, delta);
109
110 // Flip the mark at the next position as it shares the adjacency.
111 if (position + 1 < length) {
112 delta = (marks[position + 1] ^ 1) - marks[position + 1];
113 marks[position + 1] ^= 1;
114 bit.update(position + 2, delta);
115 }
116 } else {
117 int left = query[1];
118 int right = query[2];
119 // Count equal-adjacent pairs in (left, right] of the marks array.
120 answers[answerIndex++] = bit.query(right + 1) - bit.query(left + 1);
121 }
122 }
123 return answers;
124 }
125}
1261class BinaryIndexedTree {
2public:
3 int size; // Total number of positions the tree manages
4 vector<int> tree; // Internal Fenwick tree storage (1-indexed)
5
6 BinaryIndexedTree(int size)
7 : size(size)
8 , tree(size + 1, 0) {}
9
10 // Add `delta` to position `index` and propagate to affected nodes
11 void update(int index, int delta) {
12 while (index <= size) {
13 tree[index] += delta;
14 index += index & -index; // Move to the next responsible node
15 }
16 }
17
18 // Return the prefix sum from position 1 up to `index` (inclusive)
19 int query(int index) {
20 int sum = 0;
21 while (index > 0) {
22 sum += tree[index];
23 index -= index & -index; // Move to the parent node
24 }
25 return sum;
26 }
27};
28
29class Solution {
30public:
31 vector<int> minDeletions(string s, vector<vector<int>>& queries) {
32 int length = s.size();
33
34 // marks[i] == 1 means s[i] equals its previous character s[i-1].
35 // Each such adjacent equal pair requires exactly one deletion to fix.
36 vector<int> marks(length, 0);
37 BinaryIndexedTree bit(length);
38
39 // Initialize marks and the Fenwick tree based on adjacent equal pairs.
40 for (int i = 1; i < length; i++) {
41 marks[i] = (s[i] == s[i - 1]);
42 if (marks[i]) {
43 bit.update(i + 1, 1); // Tree is 1-indexed, so store at i + 1
44 }
45 }
46
47 vector<int> answer;
48
49 for (auto& query : queries) {
50 if (query[0] == 1) {
51 // Type 1: toggle the character at position `pos`.
52 // Toggling affects the equality relation at `pos` (with pos-1)
53 // and at `pos + 1` (with pos), so update both marks.
54 int pos = query[1];
55
56 // Flip the mark at `pos` and reflect the change in the tree.
57 int delta = (marks[pos] ^ 1) - marks[pos];
58 marks[pos] ^= 1;
59 bit.update(pos + 1, delta);
60
61 // Flip the mark at `pos + 1` if it exists.
62 if (pos + 1 < length) {
63 delta = (marks[pos + 1] ^ 1) - marks[pos + 1];
64 marks[pos + 1] ^= 1;
65 bit.update(pos + 2, delta);
66 }
67 } else {
68 // Type 2: count the deletions needed within range [left, right].
69 // This equals the number of marked positions in (left, right],
70 // which is the count of adjacent equal pairs in that substring.
71 int left = query[1];
72 int right = query[2];
73 answer.push_back(bit.query(right + 1) - bit.query(left + 1));
74 }
75 }
76 return answer;
77 }
78};
791// Size of the Binary Indexed Tree (Fenwick Tree)
2let treeSize: number;
3
4// 1-indexed array storing the Binary Indexed Tree
5let treeArray: number[];
6
7/**
8 * Adds `delta` to position `x` and propagates the change
9 * to all responsible nodes in the Fenwick Tree.
10 */
11function update(x: number, delta: number): void {
12 while (x <= treeSize) {
13 treeArray[x] += delta;
14 x += x & -x; // move to the next node that covers position x
15 }
16}
17
18/**
19 * Returns the prefix sum from index 1 up to index `x`.
20 */
21function query(x: number): number {
22 let sum = 0;
23 while (x > 0) {
24 sum += treeArray[x];
25 x -= x & -x; // move to the parent prefix node
26 }
27 return sum;
28}
29
30/**
31 * For each "count" query, returns the number of deletions required
32 * so that no two adjacent characters in s[l..r] are equal.
33 * A deletion is needed wherever s[i] === s[i - 1].
34 */
35function minDeletions(s: string, queries: number[][]): number[] {
36 const n = s.length;
37
38 // nums[i] = 1 means s[i] equals s[i - 1] (an adjacent duplicate pair)
39 const nums: number[] = Array(n).fill(0);
40
41 // Initialize the Fenwick Tree as a fresh global structure
42 treeSize = n;
43 treeArray = Array(n + 1).fill(0);
44
45 // Record every adjacent duplicate pair in the BIT
46 for (let i = 1; i < n; i++) {
47 if (s[i] === s[i - 1]) {
48 nums[i] = 1;
49 update(i + 1, 1);
50 }
51 }
52
53 const ans: number[] = [];
54
55 for (const q of queries) {
56 if (q[0] === 1) {
57 // Update query: flip the character at index j.
58 const j = q[1];
59
60 // Toggle the pair (j - 1, j) stored at nums[j]
61 let delta = (nums[j] ^ 1) - nums[j];
62 nums[j] ^= 1;
63 update(j + 1, delta);
64
65 // Toggle the pair (j, j + 1) stored at nums[j + 1], if it exists
66 if (j + 1 < n) {
67 delta = (nums[j + 1] ^ 1) - nums[j + 1];
68 nums[j + 1] ^= 1;
69 update(j + 2, delta);
70 }
71 } else {
72 // Count query: number of duplicate pairs within [l, r].
73 // Pairs are counted at their right index, so the valid range
74 // in BIT terms is (l + 1, r + 1].
75 const l = q[1];
76 const r = q[2];
77 ans.push(query(r + 1) - query(l + 1));
78 }
79 }
80
81 return ans;
82}
83Time and Space Complexity
-
Time Complexity:
O((n + q) × log n), wherenis the length of the strings, andqis the number of queries.The analysis is as follows:
-
Initialization phase: We iterate over the string
sfrom index1ton - 1. For each indexi, we computenums[i]inO(1)time. Whenevernums[i]is1, we callbit.update(i + 1, 1), which takesO(log n)time because the Binary Indexed Tree update operation traverses at mostlog nnodes (followingx += x & -x). Hence, this phase costsO(n × log n). -
Query phase: For each of the
qqueries:- A type
1query (update) performs at most twobit.updateoperations, each costingO(log n), for a total ofO(log n)per query. - A type
2query (range query) performs twobit.queryoperations, each costingO(log n)because the query traverses at mostlog nnodes (followingx -= x & -x), for a total ofO(log n)per query.
Therefore, processing all queries costs
O(q × log n). - A type
Combining both phases, the overall time complexity is
O(n × log n + q × log n) = O((n + q) × log n). -
-
Space Complexity:
O(n), wherenis the length of the strings.The analysis is as follows:
- The array
numsusesO(n)space. - The Binary Indexed Tree's internal array
chas sizen + 1, usingO(n)space. - The answer list
ansstores at mostqresults, but this is typically considered part of the output rather than auxiliary space.
Thus, the dominant auxiliary space usage is
O(n). - The array
Pattern Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Incorrectly Updating the Boundary Flags After a Flip
The most common mistake when handling a Flip query [1, j] is misunderstanding which nums entries actually change. Flipping s[j] does not change s[j] relative to itself — it changes how s[j] compares to its neighbors:
nums[j]encodes whethers[j] == s[j-1].nums[j+1]encodes whethers[j+1] == s[j].
Both of these comparisons involve s[j], so flipping s[j] toggles both flags. A frequent error is to only update one of them (e.g., only nums[j]), which silently corrupts the tree.
Wrong:
# Only updates one boundary — leaves nums[j+1] stale! j = q[1] delta = (nums[j] ^ 1) - nums[j] nums[j] ^= 1 bit.update(j + 1, delta)
Why a toggle works: When you flip s[j], equality with a fixed neighbor always inverts. If they were equal (nums == 1) they become different (nums == 0) and vice versa. So nums[pos] ^= 1 is always the correct transition — there is no need to re-read the actual characters.
Correct: Update both nums[j] and nums[j+1] (guarding the upper bound):
j = q[1] for pos in (j, j + 1): if 0 < pos < n: # nums[0] is never a valid pair flag delta = (nums[pos] ^ 1) - nums[pos] nums[pos] ^= 1 bit.update(pos + 1, delta)
Note:
nums[0]is always0by definition (no character precedes index0). Ifj == 0, onlynums[1]is meaningful — the loop above guards this with0 < pos. The original code is also correct becausenums[0]is never touched by a flip atj = 0in a way that affects answers (since queries[2, l, r]usebit.query(l + 1), position0’s flag is always excluded from any answer range), but the explicit0 < posguard makes the intent clearer and avoids edge-case confusion.
Pitfall 2: Off-by-One Errors in Index Mapping (0-based vs 1-based)
There are three coexisting index systems, and mixing them up is the leading source of bugs:
| Concept | Indexing |
|---|---|
String s / array nums | 0-based |
| Fenwick Tree positions | 1-based (nums[i] → tree position i+1) |
Query range [l, r] | 0-based, inclusive |
The range query must sum nums[l+1 .. r] (the internal boundaries of the substring), not nums[l .. r]:
nums[l]comparess[l]withs[l-1], buts[l-1]is outside the substring — so it must be excluded.
This gives:
bit.query(r + 1) - bit.query(l + 1)
Why excluding nums[l] matters: The minimum deletions to make s[l..r] alternating equals the number of adjacent-equal pairs strictly inside the range. The pair at index l (i.e., s[l-1], s[l]) is irrelevant because s[l-1] is not part of the substring.
Wrong variants to watch for:
bit.query(r) - bit.query(l) # both off by one bit.query(r + 1) - bit.query(l) # mistakenly includes nums[l]
Pitfall 3: Reading the Wrong Query Length
Type-1 queries have length 2 ([1, j]) while type-2 queries have length 3 ([2, l, r]). Unpacking with a fixed pattern fails:
Wrong:
_, l, r = q # crashes on a [1, j] query (not enough values to unpack)
Correct: Branch on q[0] first, then unpack each type with its own arity:
if q[0] == 1: j = q[1] ... else: _, l, r = q ...
Why the Adjacent-Pair Insight Is the Real Key
The deepest pitfall is algorithmic, not implementational: assuming you must somehow track the alternating structure of the whole substring. The crucial observation is that the minimum deletions to make a string alternating equals the count of adjacent equal pairs. Each such pair forces exactly one deletion, and removing one character of each equal pair is sufficient. Reducing the problem to "count 1s in nums[l+1..r]" is what makes the Fenwick Tree applicable and turns an apparently complex string problem into a standard range-sum-with-point-update task.
Ready to land your dream job?
Unlock your dream job with a 5-minute quiz for a personalized study roadmap!
Get My RoadmapWhat's the output of running the following function using the following tree as input?

1def serialize(root):
2 res = []
3 def dfs(root):
4 if not root:
5 res.append('x')
6 return
7 res.append(root.val)
8 dfs(root.left)
9 dfs(root.right)
10 dfs(root)
11 return ' '.join(res)
121import java.util.StringJoiner;
2
3public static String serialize(Node root) {
4 StringJoiner res = new StringJoiner(" ");
5 serializeDFS(root, res);
6 return res.toString();
7}
8
9private static void serializeDFS(Node root, StringJoiner result) {
10 if (root == null) {
11 result.add("x");
12 return;
13 }
14 result.add(Integer.toString(root.val));
15 serializeDFS(root.left, result);
16 serializeDFS(root.right, result);
17}
181function serialize(root) {
2 let res = [];
3 serialize_dfs(root, res);
4 return res.join(" ");
5}
6
7function serialize_dfs(root, res) {
8 if (!root) {
9 res.push("x");
10 return;
11 }
12 res.push(root.val);
13 serialize_dfs(root.left, res);
14 serialize_dfs(root.right, res);
15}
16Recommended Readings
Segment Tree Introduction A segment tree stores information about intervals of an array It supports two operations efficiently update one element and query an aggregate value over a contiguous range In this introduction the aggregate is sum so the operations are update k value and sum arr left right The
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion If you prefer videos here's a video that explains recursion in a fun and easy way Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask him
Want a Structured Path to Master System Design Too? Don’t Miss This!