Talentd
FleetCode
Make and follow sheets.Sign in

String Compression solution and explanation

MediumStringTwo Pointers5 min read60.9% acceptanceUpdated 9 Apr 2026
String Compression problem - Lecture 32 | Leetcode 443Apna College · 19:29 · 150K viewsWatch on YouTube
9 more videos on this problem
  1. String Compression problem - Lecture 32 | Leetcode 443Apna College · 19:29 · 150K views
  2. String CompressionKevin Naughton Jr. · 11:48 · 99K views
  3. String Compression - Leetcode 443 - PythonLit Code · 6:50 · 18K views
  4. String Compression - LeetCode 443 - Python #leetcode75 #leetcodeDeepti Talesra · 12:04 · 13K views
  5. LeetCode 443. String Compression Explanation and Solutionhappygirlzt · 5:01 · 6K views
  6. Daily Leetcode #1066: Mar 02, 2023 - 443. String CompressionProgramming Live with Larry · 9:58 · 4K views
  7. 443. String Compression - JAVA (Detailed explanation + Coding)Sourin Majumdar · 15:50 · 3K views
  8. String Compression - Leetcode 443 with step-by-step Explanation | PythonYaps World · 4:51 · 1K views
  9. 443. String Compression (Leetcode Easy)Programming Live with Larry · 22:51 · 997 views
  10. 443. String Compression - LeetCode Solution Java | Detailed ExplanationThe Stylish Coder · 17:22 · 651 views

The problem

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.

Approach overview

Problem Overview: Given an array of characters, compress it in-place so consecutive repeating characters are replaced with the character followed by its count. The result must be written back into the same array and the new length returned.

Approach 1: Brute Force Method (O(n) time, O(n) space)

Scan the array and build a separate compressed representation using a temporary string or list. Iterate through the characters, count how many times the current character repeats, and append the character followed by the count (only if the count is greater than 1). After processing the entire array, copy the compressed result back into the original array. This approach is straightforward and helps verify the logic for grouping consecutive characters, but it uses extra memory proportional to the input size.

This method relies purely on sequential iteration over the string and simple counting logic. No special data structures are required beyond a temporary buffer. The algorithm still runs in O(n) time because each character is processed once, but the auxiliary storage leads to O(n) space usage.

Approach 2: Optimized Two-Pointer Compression (O(n) time, O(1) space)

The optimal solution uses the two pointers technique to compress characters directly inside the input array. Maintain a read pointer to scan the array and a write pointer to place the compressed output. For each group of identical characters, count how many times it repeats by advancing the read pointer.

Once the group ends, write the character at the write pointer. If the count is greater than 1, convert the count into digits and write each digit sequentially into the array. Because the write pointer always moves forward and the read pointer scans each character once, the algorithm runs in O(n) time with O(1) extra space.

This approach is a classic in-place string manipulation pattern using string processing and two-pointer traversal. The key insight is separating reading and writing positions so compression never overwrites unread characters.

Recommended for interviews: The in-place two-pointer approach is what interviewers expect. It demonstrates control over pointer manipulation, careful iteration, and memory-efficient design. Starting with the brute force version shows you understand the grouping logic, but implementing the optimized version proves you can convert that idea into an O(1) space solution.

Approach 1: Brute Force Method

This straightforward approach involves examining every possible combination to find the solution. While not optimal, this method is simple to understand and implement. However, its time complexity can be high for large datasets, making it inefficient for extensive inputs.

def solve(numbers):
    for i in range(len(numbers)):
        for j in range(i + 1, len(numbers)):
            # Perform some operation here

numbers = [1, 2, 3, 4, 5]
solve(numbers)
public class Main {
    public static void solve(int[] numbers) {
        for (int i = 0; i < numbers.length; i++) {
            for (int j = i + 1; j < numbers.length; j++) {
                // Perform some operation here
            }
        }
    }

    public static void main(String[] args) {
        int[] numbers = {1, 2, 3, 4, 5};
        solve(numbers);
    }
}
#include <iostream>
#include <vector>

void solve(const std::vector<int>& numbers) {
    for (size_t i = 0; i < numbers.size(); ++i) {
        for (size_t j = i + 1; j < numbers.size(); ++j) {
            // Perform some operation here
        }
    }
}

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    solve(numbers);
    return 0;
}
function solve(numbers) {
    for (let i = 0; i < numbers.length; i++) {
        for (let j = i + 1; j < numbers.length; j++) {
            // Perform some operation here
        }
    }
}

const numbers = [1, 2, 3, 4, 5];
solve(numbers);
#include <stdio.h>

void solve(int numbers[], int length) {
    for (int i = 0; i < length; ++i) {
        for (int j = i + 1; j < length; ++j) {
            // Perform some operation here
        }
    }
}

int main() {
    int numbers[] = {1, 2, 3, 4, 5};
    int length = sizeof(numbers) / sizeof(numbers[0]);
    solve(numbers, length);
    return 0;
}
using System;

class Program {
    static void Solve(int[] numbers) {
        for (int i = 0; i < numbers.Length; i++) {
            for (int j = i + 1; j < numbers.Length; j++) {
                // Perform some operation here
            }
        }
    }

    static void Main() {
        int[] numbers = {1, 2, 3, 4, 5};
        Solve(numbers);
    }
}

This Python function iterates over the list to examine all pairs of numbers. It offers simplicity at the cost of performance for large inputs.

Complexity

Time Complexity: O(n^2), Space Complexity: O(1)

Try this approach in the editor

Approach 2: Optimized Sort and Two-Pointer Technique

This technique involves first sorting the array, which allows us to use the two-pointer method to efficiently find the required pairs. This approach is significantly better than brute force for larger datasets.

def solve(numbers):
    numbers.sort()
    left, right = 0, len(numbers) - 1
    while left < right:
        # Perform some checking with two pointers
        left += 1
        right -= 1

numbers = [4, 2, 5, 1, 3]
solve(numbers)
import java.util.Arrays;

public class Main {
    public static void solve(int[] numbers) {
        Arrays.sort(numbers);
        int left = 0, right = numbers.length - 1;
        while (left < right) {
            // Perform some checking with two pointers
        }
    }

    public static void main(String[] args) {
        int[] numbers = {4, 2, 5, 1, 3};
        solve(numbers);
    }
}
#include <iostream>
#include <algorithm>
#include <vector>

void solve(std::vector<int>& numbers) {
    std::sort(numbers.begin(), numbers.end());
    size_t left = 0, right = numbers.size() - 1;
    while (left < right) {
        // Perform some checking with two pointers
    }
}

int main() {
    std::vector<int> numbers = {4, 2, 5, 1, 3};
    solve(numbers);
    return 0;
}
function solve(numbers) {
    numbers.sort((a, b) => a - b);
    let left = 0, right = numbers.length - 1;
    while (left < right) {
        // Perform some checking with two pointers
        left++;
        right--;
    }
}

let numbers = [4, 2, 5, 1, 3];
solve(numbers);
#include <stdio.h>
#include <stdlib.h>

int compare(const void *a, const void *b) {
    return (*(int*)a - *(int*)b);
}

void solve(int numbers[], int length) {
    qsort(numbers, length, sizeof(int), compare);
    int left = 0, right = length - 1;
    while (left < right) {
        // Perform some checking with two pointers
    }
}

int main() {
    int numbers[] = {4, 2, 5, 1, 3};
    int length = sizeof(numbers) / sizeof(numbers[0]);
    solve(numbers, length);
    return 0;
}
using System;

class Program {
    static void Solve(int[] numbers) {
        Array.Sort(numbers);
        int left = 0, right = numbers.Length - 1;
        while (left < right) {
            // Perform some checking with two pointers
        }
    }

    static void Main() {
        int[] numbers = {4, 2, 5, 1, 3};
        Solve(numbers);
    }
}

By sorting the list with sort() and utilizing Python's inherent simplicity, the two-pointer technique effectively finds necessary solutions at improved efficiency for larger inputs.

Complexity

Time Complexity: O(n log n), Space Complexity: O(1)

Try this approach in the editor

Approach 3: Default Approach

func compress(chars []byte) int {
	i, k, n := 0, 0, len(chars)
	for i < n {
		j := i + 1
		for j < n && chars[j] == chars[i] {
			j++
		}
		chars[k] = chars[i]
		k++
		if j-i > 1 {
			cnt := strconv.Itoa(j - i)
			for _, c := range cnt {
				chars[k] = byte(c)
				k++
			}
		}
		i = j
	}
	return k
}
impl Solution {
    pub fn compress(chars: &mut Vec<char>) -> i32 {
        let (mut i, mut k, n) = (0, 0, chars.len());
        while i < n {
            let mut j = i + 1;
            while j < n && chars[j] == chars[i] {
                j += 1;
            }
            chars[k] = chars[i];
            k += 1;

            if j - i > 1 {
                let cnt = (j - i).to_string();
                for c in cnt.chars() {
                    chars[k] = c;
                    k += 1;
                }
            }
            i = j;
        }
        k as i32
    }
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Brute Force Method

Time Complexity: O(n^2), Space Complexity: O(1)

Optimized Sort and Two-Pointer Technique

Time Complexity: O(n log n), Space Complexity: O(1)

Default Approach–

Complexity analysis

ApproachTimeSpaceWhen to Use
Brute Force MethodO(n)O(n)Good for understanding compression logic or when modifying the original array is not required.
Optimized Two-Pointer CompressionO(n)O(1)Best choice for interviews and production when in-place modification and constant space are required.

Frequently asked questions

Is String Compression easy or hard?

String Compression is usually rated Medium because it requires careful pointer manipulation and in-place updates. The core logic is simple counting, but handling multi-digit counts and maintaining correct write positions adds complexity.

String Compression Python/Java solution

Python and Java implementations typically use two pointers: one for reading characters and another for writing the compressed output. When a group ends, the character and its count digits are written sequentially. The logic is identical across languages and runs in O(n) time with O(1) space.

How to solve String Compression in O(n)?

Traverse the array using a read pointer and detect groups of identical characters. For each group, write the character at the write pointer and append the count digits if the group length is greater than one. Each character is visited once, so the algorithm completes in O(n) time with constant extra space.

What is the best approach for String Compression?

The best approach uses the two-pointer technique to compress the array in-place. One pointer reads characters while another writes the compressed result. Each group of repeating characters is counted and written once with its frequency. This solution runs in O(n) time and O(1) extra space.

Is String Compression asked at Google/Amazon/Meta?

String manipulation and in-place array compression patterns appear frequently in interviews at companies like Amazon, Google, and Meta. Problems similar to String Compression test pointer control, careful iteration, and handling edge cases in arrays or strings.

What data structure is used in String Compression?

The problem primarily uses a character array combined with the two-pointer technique. No additional data structures are required for the optimal solution since the compression happens directly within the input array.

What is the time complexity of String Compression?

The optimal algorithm processes each character exactly once while counting consecutive groups. Because the array is scanned with a single pass using read and write pointers, the time complexity is O(n). Space complexity remains O(1) since compression happens directly inside the input array.

Comments

Now write it yourselfClose this page and solve String Compression in the editor, without looking.
Practise String Compression