Facebook Pixel

2716. Minimize String Length

EasyHash TableString
Leetcode Link

Problem Description

You are given a string s and can perform two types of operations on it:

  1. Delete left neighbor: Choose an index i in the string. Let c be the character at position i. Delete the closest occurrence of character c that appears to the left of position i (if such an occurrence exists).

  2. Delete right neighbor: Choose an index i in the string. Let c be the character at position i. Delete the closest occurrence of character c that appears to the right of position i (if such an occurrence exists).

You can perform these operations zero or more times in any order. Your goal is to minimize the length of the string after performing these operations.

Return the minimum possible length of the string.

Key Insight: When you choose a character at position i, you can delete another occurrence of the same character either to its left or right. This means that for any character that appears multiple times, you can keep reducing its occurrences until only one remains. No matter which occurrences you choose to delete or in what order, you'll always end up with at least one occurrence of each distinct character. Since you cannot delete the last remaining occurrence of any character (there would be no matching character to the left or right), the minimum length equals the number of distinct characters in the string.

For example, if s = "aaabc", you can:

  • Choose index 1 (character 'a'), delete the 'a' at index 0
  • Choose index 1 (character 'a'), delete the 'a' at index 2
  • Final string: "abc" with length 3

The solution simply returns len(set(s)), which counts the number of unique characters in the string.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

Let's think about what happens when we perform these operations. When we select a character at position i, we can only delete another occurrence of the same character - either to its left or right. This is the crucial observation.

Consider a character that appears multiple times in the string, say 'a' appears 5 times. By repeatedly choosing positions with 'a' and deleting neighboring 'a's, we can reduce the count from 5 → 4 → 3 → 2 → 1. But we can never go from 1 → 0, because when only one 'a' remains, there's no other 'a' to its left or right to delete.

This pattern holds for every distinct character in the string. No matter how many times a character appears initially, we can always reduce it down to exactly one occurrence, but never to zero.

Let's trace through another example: s = "aabcbaa"

  • Character 'a' appears 4 times → can be reduced to 1
  • Character 'b' appears 2 times → can be reduced to 1
  • Character 'c' appears 1 time → stays at 1 (can't delete it)

The minimum possible string would have exactly one occurrence of each distinct character: one 'a', one 'b', and one 'c', giving us a length of 3.

This leads us to realize that the minimum length is simply the count of distinct characters in the original string. The order of operations doesn't matter - we'll always end up with the same minimum length. That's why the solution is elegantly simple: len(set(s)), which counts the unique characters.

Solution Approach

The solution uses a hash table (or set) data structure to count the number of distinct characters in the string. This is the most straightforward approach once we understand that the problem reduces to finding unique characters.

Implementation Details:

The Python solution leverages the built-in set() data structure:

class Solution:
    def minimizedStringLength(self, s: str) -> int:
        return len(set(s))

Here's how it works:

  1. Convert string to set: set(s) creates a set from the string s. When a string is converted to a set, it automatically removes all duplicate characters, keeping only one instance of each unique character.

  2. Count unique elements: len(set(s)) returns the size of the set, which equals the number of distinct characters.

Why this works:

  • A set is an unordered collection that stores only unique elements
  • When we pass a string to set(), it iterates through each character and adds it to the set
  • Duplicate characters are automatically ignored (set property)
  • The resulting set contains exactly one instance of each distinct character

Time Complexity: O(n) where n is the length of the string, as we need to iterate through all characters once to build the set.

Space Complexity: O(k) where k is the number of distinct characters in the string. In the worst case where all characters are unique, k = n, giving us O(n) space complexity.

This approach is optimal because we must examine every character at least once to determine the distinct characters, and the set provides the most efficient way to track uniqueness.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution with the string s = "abbaca".

Step 1: Identify the distinct characters

  • The string contains: 'a' (appears 3 times), 'b' (appears 2 times), 'c' (appears 1 time)

Step 2: Understanding possible operations

  • We can choose any 'a' and delete another 'a' to its left or right
  • We can choose any 'b' and delete another 'b' to its left or right
  • We cannot delete 'c' since there's only one occurrence

Step 3: Simulating the reduction process

Starting string: "abbaca" (length 6)

One possible sequence of operations:

  • Choose index 0 ('a'), delete the 'a' at index 3 → "bbbca" (length 5)
  • Choose index 0 ('b'), delete the 'b' at index 1 → "bbca" (length 4)
  • Choose index 3 ('a'), delete the 'a' at index 2 → "bbc" (length 3)

We're left with one 'b' and one 'c', but we still have an 'a' at the end that we haven't accounted for. Let me reconsider:

Starting string: "abbaca" (length 6)

  • Choose index 3 ('a'), delete the 'a' at index 0 → "bbaca" (length 5)
  • Choose index 3 ('a'), delete the 'a' at index 2 → "bbca" (length 4)
  • Choose index 0 ('b'), delete the 'b' at index 1 → "bca" (length 3)

Final result: "bca" - exactly one of each distinct character!

Step 4: Apply the solution approach

s = "abbaca"
unique_chars = set(s)  # {'a', 'b', 'c'}
result = len(unique_chars)  # 3

The set automatically identifies the 3 distinct characters ('a', 'b', 'c'), giving us the minimum possible length of 3. This matches what we achieved through manual operations, confirming that no matter how we perform the deletions, we'll always end up with at least one of each distinct character.

Solution Implementation

1class Solution:
2    def minimizedStringLength(self, s: str) -> int:
3        """
4        Calculate the minimum possible length of string after applying operations.
5      
6        The operation allows choosing any character 'c' and removing its closest 
7        occurrences on both left and right sides. The minimum length is achieved 
8        when we keep exactly one occurrence of each unique character.
9      
10        Args:
11            s: Input string consisting of lowercase English letters
12          
13        Returns:
14            The minimum possible length of the string after operations
15        """
16        # Convert string to set to get unique characters
17        # The minimum length equals the number of distinct characters
18        unique_characters = set(s)
19      
20        # Return the count of unique characters
21        return len(unique_characters)
22
1class Solution {
2    /**
3     * Calculates the minimum possible length of a string after removing duplicate characters.
4     * The algorithm counts the number of unique characters in the input string.
5     * 
6     * @param s the input string to process
7     * @return the count of unique characters in the string
8     */
9    public int minimizedStringLength(String s) {
10        // Use a HashSet to store unique characters from the string
11        Set<Character> uniqueCharacters = new HashSet<>();
12      
13        // Iterate through each character in the string
14        for (int i = 0; i < s.length(); i++) {
15            // Add the current character to the set (duplicates are automatically ignored)
16            uniqueCharacters.add(s.charAt(i));
17        }
18      
19        // Return the number of unique characters
20        return uniqueCharacters.size();
21    }
22}
23
1class Solution {
2public:
3    /**
4     * Calculates the minimized length of a string after removing duplicate characters.
5     * 
6     * @param s The input string to process
7     * @return The count of unique characters in the string
8     */
9    int minimizedStringLength(string s) {
10        // Create an unordered_set from the string to automatically remove duplicates
11        // The set constructor iterates through the string and keeps only unique characters
12        unordered_set<char> uniqueChars(s.begin(), s.end());
13      
14        // Return the size of the set, which represents the number of unique characters
15        return uniqueChars.size();
16    }
17};
18
1/**
2 * Calculates the minimized length of a string after removing duplicate characters.
3 * The function counts the number of unique characters in the input string.
4 * 
5 * @param s - The input string to process
6 * @returns The count of unique characters in the string
7 */
8function minimizedStringLength(s: string): number {
9    // Convert string to array of characters
10    const characters: string[] = s.split('');
11  
12    // Create a Set to automatically remove duplicates
13    const uniqueCharacters: Set<string> = new Set(characters);
14  
15    // Return the size of the Set (number of unique characters)
16    return uniqueCharacters.size;
17}
18

Time and Space Complexity

The time complexity is O(n), where n is the length of the string s. This is because converting a string to a set requires iterating through each character in the string exactly once to build the set.

The space complexity is O(|Σ|), where Σ is the character set. Since the problem deals with lowercase English letters, |Σ| = 26. In the worst case, the set will contain at most 26 unique characters regardless of the input string length, making the space complexity O(26) which simplifies to O(1) constant space.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

Pitfall 1: Misunderstanding the Problem as a Greedy Deletion Problem

The Mistake: Many developers initially approach this problem by trying to implement the actual deletion operations, thinking they need to:

  • Track indices and perform actual deletions
  • Decide which neighbor (left or right) to delete for optimal results
  • Maintain the string state after each operation

Example of Incorrect Approach:

def minimizedStringLength(self, s: str) -> int:
    s_list = list(s)
    changed = True
    while changed:
        changed = False
        for i in range(len(s_list)):
            if s_list[i] is None:
                continue
            # Try to find and delete left neighbor
            for j in range(i-1, -1, -1):
                if s_list[j] == s_list[i]:
                    s_list[j] = None
                    changed = True
                    break
            # Complex logic continues...
    return len([c for c in s_list if c is not None])

Why This is Wrong: This approach is unnecessarily complex and inefficient. The problem doesn't require simulating the operations; it only asks for the final minimum length.

The Solution: Recognize that regardless of the order of operations, you can always reduce any character that appears multiple times down to a single occurrence. The key insight is that the minimum length is simply the count of distinct characters.

Pitfall 2: Overthinking Edge Cases

The Mistake: Worrying about special scenarios like:

  • What if the string has only one character repeated multiple times?
  • What about the order of characters after operations?
  • Should we preserve the relative positions of remaining characters?

Example Concern:

# Unnecessary edge case handling
def minimizedStringLength(self, s: str) -> int:
    if len(s) == 0:
        return 0
    if len(s) == 1:
        return 1
    if all(c == s[0] for c in s):  # All same character
        return 1
    # ... more unnecessary checks
    return len(set(s))

Why This is Wrong: The set() approach naturally handles all these cases:

  • Empty string: set("") returns an empty set with length 0
  • Single character: set("a") returns a set with one element
  • All same characters: set("aaaa") returns a set with one element
  • Mixed characters: Works correctly for any combination

The Solution: Trust that the mathematical property (minimum length = distinct characters) applies universally without special cases.

Pitfall 3: Using Inefficient Data Structures

The Mistake: Using a dictionary or manual counting instead of a set:

def minimizedStringLength(self, s: str) -> int:
    char_count = {}
    for char in s:
        char_count[char] = char_count.get(char, 0) + 1
    return len(char_count)

Or using a list to track unique characters:

def minimizedStringLength(self, s: str) -> int:
    unique = []
    for char in s:
        if char not in unique:
            unique.append(char)
    return len(unique)

Why This is Suboptimal:

  • The dictionary approach wastes space storing counts we don't need
  • The list approach has O(n²) time complexity due to the in operation being O(n) for lists

The Solution: Use set(s) which is specifically designed for tracking unique elements with O(1) average-case insertion and lookup, making it both the simplest and most efficient approach.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Given a sorted array of integers and an integer called target, find the element that equals to the target and return its index. Select the correct code that fills the ___ in the given code snippet.

1def binary_search(arr, target):
2    left, right = 0, len(arr) - 1
3    while left ___ right:
4        mid = (left + right) // 2
5        if arr[mid] == target:
6            return mid
7        if arr[mid] < target:
8            ___ = mid + 1
9        else:
10            ___ = mid - 1
11    return -1
12
1public static int binarySearch(int[] arr, int target) {
2    int left = 0;
3    int right = arr.length - 1;
4
5    while (left ___ right) {
6        int mid = left + (right - left) / 2;
7        if (arr[mid] == target) return mid;
8        if (arr[mid] < target) {
9            ___ = mid + 1;
10        } else {
11            ___ = mid - 1;
12        }
13    }
14    return -1;
15}
16
1function binarySearch(arr, target) {
2    let left = 0;
3    let right = arr.length - 1;
4
5    while (left ___ right) {
6        let mid = left + Math.trunc((right - left) / 2);
7        if (arr[mid] == target) return mid;
8        if (arr[mid] < target) {
9            ___ = mid + 1;
10        } else {
11            ___ = mid - 1;
12        }
13    }
14    return -1;
15}
16

Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More