Loading problems...
TL;DR: Iterate through the array using a read pointer to identify groups of consecutive characters and a write pointer to overwrite the array in-place with the compressed format.
The String Compression problem requires performing Run-Length Encoding on a character array. The task is to replace consecutive repeating characters with the character itself followed by the count of repetitions. If a character appears only once, it is appended without a count. Crucially, this operation must be performed in-place on the input array chars, and the algorithm must return the new length of the modified array.
This is a popular interview question (LeetCode 443) that tests a candidate's ability to manipulate array pointers efficiently under strict space constraints.
A naive approach to solving String Compression involves using auxiliary space to build the result.
result.chars array.result.result back into the original chars array and return the length.Pseudo-code:
textfunction compress(chars): string res = "" i = 0 while i < length(chars): char c = chars[i] count = 0 while i < length(chars) and chars[i] == c: count++ i++ res += c if count > 1: res += string(count) for j from 0 to length(res): chars[j] = res[j] return length(res)
Why this fails: While this solution is logically correct and runs in linear time , it has a Space Complexity of because it creates a separate string/list proportional to the size of the input. The problem explicitly constraints the solution to use O(1) constant extra space. Therefore, a brute force approach that allocates new storage for the compressed string is suboptimal and may be rejected in an interview setting.
The core insight for solving LeetCode 443 efficiently lies in the realization that the compressed version of any character group is always shorter than or equal in length to the original group (with the exception of single characters, which remain length 1).
Because the compressed data is generated sequentially and is generally shorter than the source data, we can safely overwrite the beginning of the array with the compressed result while we are still reading the rest of the array.
The algorithm relies on maintaining a strict invariant:
i): Scans the array to determine the extent of the current group of identical characters.write_index): Marks the position where the next piece of compressed data (character or digit) should be stored.Visual Description:
Imagine the array as a tape. The read head moves forward rapidly, counting how many times a character repeats. Once the read head hits a different character, the write head (which is lagging behind) records the character and the count. The write head then advances. Because we process groups from left to right, the write head will never overtake the read head, preventing data corruption.

To implement this strategy for String Compression, we follow these rules:
write pointer at index 0.read pointer (often the loop variable i) to iterate through the array.read:
count.chars[write] and increment write.count is greater than 1, convert the integer count into string format.chars[write] and incrementing write each time.write pointer represents the new length of the compressed array.This approach ensures we satisfy the O(1) space constraint by utilizing the input array itself as the storage buffer.
Let's trace the algorithm with chars = ["a", "a", "b", "b", "c", "c", "c"]:
i = 0, write = 0.i points to first 'a'. We scan forward until we hit 'b' or end of array.count = 2.chars[0]. write becomes 1.count > 1, so we convert 2 to "2". Write '2' at chars[1]. write becomes 2.i past the group of 'a's.i points to first 'b'. Scan forward.count = 2.chars[2]. write becomes 3.count > 1, write '2' at chars[3]. write becomes 4.i past the group of 'b's.i points to first 'c'. Scan forward.count = 3.chars[4]. write becomes 5.count > 1, write '3' at chars[5]. write becomes 6.i past the group of 'c's.i has reached the end of the array. Return write (which is 6).The array effectively becomes ["a", "2", "b", "2", "c", "3", "c"], but since we return length 6, the consumer only sees the valid prefix.
The correctness relies on the fact that write <= read at all times.
['x']), we write 'x' and advance write by 1. The read pointer also advances by 1. No overwrite occurs.aa (len 2) -> a2 (len 2).aaaaaaaaaaaa (len 12) -> a12 (len 3).Since the compressed form never exceeds the original length of the group, the write pointer never overtakes the start of the next unprocessed group. Thus, we never overwrite data that hasn't been read yet.
cpp#include <vector> #include <string> class Solution { public: int compress(std::vector<char>& chars) { int write = 0; int i = 0; while (i < chars.size()) { char currentChar = chars[i]; int count = 0; // Count consecutive characters while (i < chars.size() && chars[i] == currentChar) { i++; count++; } // Write the character chars[write++] = currentChar; // If count > 1, write the digits if (count > 1) { std::string countStr = std::to_string(count); for (char c : countStr) { chars[write++] = c; } } } return write; } };
javaclass Solution { public int compress(char[] chars) { int write = 0; int i = 0; while (i < chars.length) { char currentChar = chars[i]; int count = 0; // Count consecutive characters while (i < chars.length && chars[i] == currentChar) { i++; count++; } // Write the character chars[write++] = currentChar; // If count > 1, write the digits if (count > 1) { String countStr = Integer.toString(count); for (char c : countStr.toCharArray()) { chars[write++] = c; } } } return write; } }
pythonclass Solution: def compress(self, chars: List[str]) -> int: write = 0 i = 0 while i < len(chars): current_char = chars[i] count = 0 # Count consecutive characters while i < len(chars) and chars[i] == current_char: i += 1 count += 1 # Write the character chars[write] = current_char write += 1 # If count > 1, write the digits if count > 1: for digit in str(count): chars[write] = digit write += 1 return write
Time Complexity:
We iterate through the array with the read pointer exactly once. The inner loop that finds the end of a group advances the read pointer, ensuring each character is visited a constant number of times. The write pointer also moves linearly. Thus, the time complexity is linear with respect to the input size .
Space Complexity:
We modify the chars array in-place. The only extra space used is for a few integer variables (i, write, count) and a temporary buffer to convert the count integer to characters (which is negligible, max 4 digits for length 2000). This satisfies the constant space constraint.
The Two Pointers - In-place Array Modification pattern is fundamental for optimizing space in array problems.
s += c) inside the loop in languages where strings are immutable (like Java or Python), or repeatedly inserting elements into the array (shifting elements times).chars[write++] = (char)(count + '0').while loop, checking chars[i] == currentChar without first checking i < chars.length.chars.length or the read pointer instead of the write pointer.