# 443. String Compression - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions Visit original link: [443. String Compression - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.to/en/leetcode/443-string-compression) for a better experience! LeetCode link: [443. String Compression](https://leetcode.com/problems/string-compression), difficulty: **Medium**. ## LeetCode description of "443. String Compression" Given an array of characters `chars`, compress it using the following algorithm: Begin with an empty string `s`. For each group of **consecutive repeating characters** in `chars`: - If the group's length is `1`, append the character to `s`. - Otherwise, append the character followed by the group's length. The compressed string `s` **should not be returned separately**, but instead, be stored **in the input character array** `chars`. Note that group lengths that are `10` or longer will be split into multiple characters in `chars`. After you are done **modifying the input array**, return *the new length of the array*. You must write an algorithm that uses only constant extra space. ### [Example 1] **Input**: `chars = ["a","a","b","b","c","c","c"]` **Output**: `Return 6, and the first 6 characters of the input array should be: ["a","2","b","2","c","3"]` **Explanation**:

The groups are "aa", "bb", and "ccc". This compresses to "a2b2c3".

### [Example 2] **Input**: `chars = ["a"]` **Output**: `Return 1, and the first character of the input array should be: ["a"]` **Explanation**:

The only group is "a", which remains uncompressed since it's a single character.

### [Example 3] **Input**: `chars = ["a","b","b","b","b","b","b","b","b","b","b","b","b"]` **Output**: `Return 4, and the first 4 characters of the input array should be: ["a","b","1","2"].` **Explanation**:

The groups are "a" and "bbbbbbbbbbbb". This compresses to "ab12".

### [Constraints] - `1 <= chars.length <= 2000` - `chars[i]` is a lowercase English letter, uppercase English letter, digit, or symbol. ### [Hints]
Hint 1 How do you know if you are at the end of a consecutive group of characters?
## Intuition We use two pointers (a read pointer `fast` and a write pointer `slow`) and a counter `count` to achieve in-place compression. 1. **Initialization**: - Append a sentinel character (e.g., a space " ") to the end of the input array `chars`. This ensures that the last group of consecutive characters can also be correctly processed within the loop. Java and C# is a little different because array is fixed size. - `slow = 0`: The `slow` pointer points to the starting character of the current write segment, and it also represents the length of the final compressed array. - `count = 1`: Records the number of occurrences of the current consecutive character `chars[slow]`. 2. **Traversal and Compression**: - The `fast` pointer starts traversing the array `chars` from index `1` (until the sentinel character). - **Case 1: Character Repetition** (`chars[fast]` is equal to `chars[slow]`) - Increment `count`. - **Case 2: Character Not Repeated** (`chars[fast]` is not equal to `chars[slow]`) - **Subcase 1: Count is 1** - Please implement it by yourself - **Subcase 2: Count is greater than 1** - Please implement it by yourself 3. **Return Result**: - After the `fast` pointer has traversed the entire array (including the sentinel), the value of the `slow` pointer is the new length of the compressed array. ## Pattern of "Fast & Slow Pointers Technique" ```java int slow = 0; // slow pointer // ... for (int fast = 1; fast < array_length; fast++) { // This line is the key! if (condition_1) { // ... continue; // 'continue' is better than 'else' because 'else' will introduce more indents } if (condition_2) { // ... continue; // 'continue' is better than 'else' } // condition_3 // ... slow++; // ... } return something; ``` ## Complexity - Time complexity: `O(N)`. - Space complexity: `O(1)`. ## Python ```python class Solution: def compress(self, chars: List[str]) -> int: chars.append(" ") # Append an extra special char to process the last char easier slow = 0 # Slow pointer. This is the answer. count = 1 # Count of consecutive repeating characters for fast in range(1, len(chars)): if chars[fast] == chars[slow]: count += 1 continue # 'continue' is better than 'else' because 'else' will introduce more indents if count == 1: slow += 1 # Don't need to append the 'count' when count is 1. chars[slow] = chars[fast] continue # 'continue' is better than 'else' because 'else' will introduce more indents # Append the 'count' for c in str(count): slow += 1 chars[slow] = c slow += 1 chars[slow] = chars[fast] count = 1 return slow ``` ## Java ```java import java.util.ArrayList; import java.util.List; class Solution { public int compress(char[] chars) { int slow = 0; // Slow pointer. This is the answer. int count = 1; // Count of consecutive repeating characters for (int fast = 1; fast <= chars.length; fast++) { // it is "<=", not "<" var charFast = (fast == chars.length ? ' ' : chars[fast]); if (charFast == chars[slow]) { count++; continue; // 'continue' is better than 'else' because 'else' will introduce more indents } if (count == 1) { slow++; // Don't need to append the 'count' when count is 1. if (slow < chars.length) { chars[slow] = charFast; } continue; // 'continue' is better than 'else' because 'else' will introduce more indents } // Append the 'count' for (char c : String.valueOf(count).toCharArray()) { slow++; chars[slow] = c; } slow++; if (slow < chars.length) { chars[slow] = charFast; } count = 1; } return slow; } } ``` ## C++ ```cpp class Solution { public: int compress(vector& chars) { chars.push_back(' '); // Append an extra special char to process the last char easier int slow = 0; // Slow pointer. This is the answer. int count = 1; // Count of consecutive repeating characters for (int fast = 1; fast < chars.size(); ++fast) { if (chars[fast] == chars[slow]) { count++; continue; // 'continue' is better than 'else' because 'else' will introduce more indents } if (count == 1) { slow++; // Don't need to append the 'count' when count is 1. chars[slow] = chars[fast]; continue; // 'continue' is better than 'else' because 'else' will introduce more indents } // Append the 'count' for (char c : to_string(count)) { slow++; chars[slow] = c; } slow++; chars[slow] = chars[fast]; count = 1; } return slow; } }; ``` ## C# ```csharp public class Solution { public int Compress(char[] chars) { int slow = 0; // Slow pointer. This is the answer. int count = 1; // Count of consecutive repeating characters for (int fast = 1; fast <= chars.Length; fast++) { // it is "<=", not "<" char charFast = (fast == chars.Length ? ' ' : chars[fast]); if (charFast == chars[slow]) { count++; continue; // 'continue' is better than 'else' because 'else' will introduce more indents } if (count == 1) { slow++; // Don't need to append the 'count' when count is 1. if (slow < chars.Length) { chars[slow] = charFast; } continue; // 'continue' is better than 'else' because 'else' will introduce more indents } // Append the 'count' foreach (char c in count.ToString()) { slow++; chars[slow] = c; } slow++; if (slow < chars.Length) { chars[slow] = charFast; } count = 1; } return slow; } } ``` ## JavaScript ```javascript /** * @param {character[]} chars * @return {number} */ var compress = function(chars) { chars.push(' ') // Append an extra special char to process the last char easier let slow = 0 // Slow pointer. This is the answer. let count = 1 // Count of consecutive repeating characters for (let fast = 1; fast < chars.length; fast++) { if (chars[fast] === chars[slow]) { count++ continue // 'continue' is better than 'else' because 'else' will introduce more indents } if (count === 1) { slow++ // Don't need to append the 'count' when count is 1. chars[slow] = chars[fast] continue // 'continue' is better than 'else' because 'else' will introduce more indents } // Append the 'count' for (const c of count.toString()) { slow++ chars[slow] = c } slow++ chars[slow] = chars[fast] count = 1 } return slow } ``` ## Go ```go // A test cannot pass. Reason is still unknown func compress(chars []byte) int { chars = append(chars, ' ') // Append an extra special char to process the last char easier slow := 0 // Slow pointer. This is the answer. count := 1 // Count of consecutive repeating characters for fast := 1; fast < len(chars); fast++ { if chars[fast] == chars[slow] { count++ continue // 'continue' is better than 'else' because 'else' will introduce more indents } if count == 1 { slow++ // Don't need to append the 'count' when count is 1. chars[slow] = chars[fast] continue // 'continue' is better than 'else' because 'else' will introduce more indents } // Append the 'count' for _, c := range strconv.Itoa(count) { slow++ chars[slow] = byte(c) } slow++ chars[slow] = chars[fast] count = 1 } return slow } ``` ## Ruby ```ruby # @param {Character[]} chars # @return {Integer} def compress(chars) chars << " " # Append an extra special char to process the last char easier slow = 0 # Slow pointer. This is the answer. count = 1 # Count of consecutive repeating characters (1...chars.length).each do |fast| if chars[fast] == chars[slow] count += 1 next # 'next' is better than 'else' because 'else' will introduce more indents end if count == 1 slow += 1 # Don't need to append the 'count' when count is 1. chars[slow] = chars[fast] next # 'next' is better than 'else' because 'else' will introduce more indents end # Append the 'count' count.to_s.each_char do |c| slow += 1 chars[slow] = c end slow += 1 chars[slow] = chars[fast] count = 1 end slow end ``` ## Other languages ```java // Welcome to create a PR to complete the code of this language, thanks! ``` Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCode.to](https://leetcode.to): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time! Original link: [443. String Compression - LeetCode Python/Java/C++/JS/C#/Go/Ruby Solutions](https://leetcode.to/en/leetcode/443-string-compression). GitHub repository: [leetcode-python-java](https://github.com/leetcode-python-java/leetcode-python-java).