This is a run-length encoding problem with one extra requirement: we have to do the compression in-place, writing the result back into the same array we read from, using only constant extra space.
We group consecutive identical characters. For each group, we write the character itself, then write the count only if the group has more than one character. When the count is 10 or more, each digit of the count is written as a separate character, so a run of 12 b's becomes ['b', '1', '2'], not ['b', '12'].
The compressed output is always shorter than or equal to the original input. A single character stays length 1. A group of 2 becomes length 2 (character + "2"). A group of 3 or more always shrinks. This is what makes the in-place version possible: we can write the compressed result into the same array without ever overwriting characters we have not processed yet, as long as one pointer reads and another writes.
1 <= chars.length <= 2000 → Performance is not the binding constraint here. The constant extra space requirement is, since it rules out building the result in a new array.chars[i] can be lowercase, uppercase, digit, or symbol → Any character is valid, so the algorithm cannot assume the array contains only letters. Counts written as digits sit in the same array as the characters being counted.Set the in-place requirement aside for a moment and build the compressed result in a separate list. Walk through the array, count each run of consecutive characters, and append the character (plus its count if greater than 1) to the result list. Then copy everything back into the original array.
This violates the O(1) space constraint, but it isolates the counting and digit-writing logic before we fold the read and write back into a single array.
i starting at index 0.i is within bounds:i for each match).chars.Loading animation...
This is correct but uses O(n) extra space. Because the compressed output is never longer than the original, the result can go directly into the input array using two pointers, which removes the extra list.
Since the compressed form is never longer than the original input, we write the result directly into chars while reading from it, using two pointers. A read pointer scans the array to identify groups of consecutive characters, and a write pointer marks where the next compressed character goes.
The write pointer always stays at or behind the read pointer, so by the time we write to a position we have already read past it. That is what keeps the overwrite safe.
After processing a group ending at read index r, the write pointer sits at some index w. The compressed form of every group seen so far has length less than or equal to the number of original characters consumed, so w <= r holds as an invariant. A group of size 1 writes 1 character, a group of size 2 through 9 writes 2 characters (the count is 1 digit, never longer than the group), and a group of size 10 through 99 writes 3 characters. The count's digit length is always at most the group size, so w never passes r, and no unread character is overwritten before it is read.
write pointer at 0 and a read pointer at 0.read is within bounds:chars[read].read while the character matches.chars[write] and increment write.write (the new length of the compressed array).Loading animation...