LeetCodee

443. String Compression

Jump to Solution: Python Java C++ JavaScript C#

Problem Description

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.

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 "bbbbbbbbbbbbb". This compresses to "ab12".

Constraints:

  • 1 <= chars.length <= 2000
  • chars[i] is a lowercase English letter, uppercase English letter, digit, or symbol.

Solution

Python Solution

class Solution:
    def compress(self, chars: List[str]) -> int:
        write = 0  # Position to write compressed characters
        anchor = 0  # Start of the current group
        
        for read, char in enumerate(chars):
            # If we're at the end of the array or a different character
            if read + 1 == len(chars) or chars[read + 1] != char:
                chars[write] = chars[anchor]  # Write the character
                write += 1
                
                if read > anchor:  # If there was more than one character
                    count = read - anchor + 1
                    # Convert the count to string and write each digit
                    for digit in str(count):
                        chars[write] = digit
                        write += 1
                
                anchor = read + 1  # Move anchor to start of next group
        
        return write

Time Complexity: O(n)

Where n is the length of the input array.

Space Complexity: O(1)

Only using constant extra space.

Java Solution

class Solution {
    public int compress(char[] chars) {
        int write = 0;  // Position to write compressed characters
        int anchor = 0;  // Start of the current group
        
        for (int read = 0; read < chars.length; read++) {
            // If we're at the end of the array or a different character
            if (read + 1 == chars.length || chars[read + 1] != chars[read]) {
                chars[write++] = chars[anchor];  // Write the character
                
                if (read > anchor) {  // If there was more than one character
                    String count = String.valueOf(read - anchor + 1);
                    // Write each digit of the count
                    for (char c : count.toCharArray()) {
                        chars[write++] = c;
                    }
                }
                
                anchor = read + 1;  // Move anchor to start of next group
            }
        }
        
        return write;
    }
}

Time Complexity: O(n)

Where n is the length of the input array.

Space Complexity: O(1)

Only using constant extra space.

C++ Solution

class Solution {
public:
    int compress(vector& chars) {
        int write = 0;  // Position to write compressed characters
        int anchor = 0;  // Start of the current group
        
        for (int read = 0; read < chars.size(); read++) {
            // If we're at the end of the array or a different character
            if (read + 1 == chars.size() || chars[read + 1] != chars[read]) {
                chars[write++] = chars[anchor];  // Write the character
                
                if (read > anchor) {  // If there was more than one character
                    string count = to_string(read - anchor + 1);
                    // Write each digit of the count
                    for (char c : count) {
                        chars[write++] = c;
                    }
                }
                
                anchor = read + 1;  // Move anchor to start of next group
            }
        }
        
        return write;
    }
};

Time Complexity: O(n)

Where n is the length of the input array.

Space Complexity: O(1)

Only using constant extra space.

JavaScript Solution

/**
 * @param {character[]} chars
 * @return {number}
 */
var compress = function(chars) {
    let write = 0;  // Position to write compressed characters
    let anchor = 0;  // Start of the current group
    
    for (let read = 0; read < chars.length; read++) {
        // If we're at the end of the array or a different character
        if (read + 1 === chars.length || chars[read + 1] !== chars[read]) {
            chars[write++] = chars[anchor];  // Write the character
            
            if (read > anchor) {  // If there was more than one character
                const count = String(read - anchor + 1);
                // Write each digit of the count
                for (const digit of count) {
                    chars[write++] = digit;
                }
            }
            
            anchor = read + 1;  // Move anchor to start of next group
        }
    }
    
    return write;
};

Time Complexity: O(n)

Where n is the length of the input array.

Space Complexity: O(1)

Only using constant extra space.

C# Solution

public class Solution {
    public int Compress(char[] chars) {
        int write = 0;  // Position to write compressed characters
        int anchor = 0;  // Start of the current group
        
        for (int read = 0; read < chars.Length; read++) {
            // If we're at the end of the array or a different character
            if (read + 1 == chars.Length || chars[read + 1] != chars[read]) {
                chars[write++] = chars[anchor];  // Write the character
                
                if (read > anchor) {  // If there was more than one character
                    string count = (read - anchor + 1).ToString();
                    // Write each digit of the count
                    foreach (char c in count) {
                        chars[write++] = c;
                    }
                }
                
                anchor = read + 1;  // Move anchor to start of next group
            }
        }
        
        return write;
    }
}

Time Complexity: O(n)

Where n is the length of the input array.

Space Complexity: O(1)

Only using constant extra space.

Approach Explanation

The solution uses a two-pointer approach with read and write pointers:

  1. Key Insights:
    • Two-pointer technique
    • In-place modification
    • Group counting
    • Character handling
  2. Algorithm Steps:
    • Track positions
    • Count groups
    • Write characters
    • Handle counts

Implementation Details:

  • Position tracking
  • Group detection
  • Count conversion
  • Array modification

Optimization Insights:

  • In-place update
  • Single pass
  • Memory efficiency
  • Early termination

Edge Cases:

  • Single character
  • Long sequences
  • No repeats
  • All repeats