Facebook Pixel

1400. Construct K Palindrome Strings

MediumGreedyHash TableStringCounting
Leetcode Link

Problem Description

You are given a string s and an integer k. Your task is to determine if you can use all the characters in s to construct exactly k non-empty palindrome strings.

A palindrome string reads the same forwards and backwards (like "aba", "racecar", or even single characters like "a").

You need to return true if it's possible to use every character from s to form exactly k palindromes, or false otherwise.

For example:

  • If s = "annabelle" and k = 2, you could form palindromes like "anna" and "belle" isn't a palindrome, but you could rearrange to form "anna" and "blleb", so this would return true.
  • If s = "abc" and k = 1, you cannot form a single palindrome using all three characters since they're all different.

The key insight is that in a palindrome, characters must appear in pairs (they can be mirrored), except for at most one character that can sit in the middle. So if you have too many characters with odd counts compared to the number of palindromes you need to form, it becomes impossible.

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

Intuition

Let's think about what makes a palindrome. In any palindrome, characters must appear in matching pairs that mirror each other, except for potentially one character in the middle (for odd-length palindromes).

For example:

  • "aba" - the 'a' appears twice (forms a pair), 'b' appears once (sits in middle)
  • "abba" - both 'a' and 'b' appear twice (form pairs)
  • "racecar" - 'r', 'a', 'c' appear twice (form pairs), 'e' appears once (sits in middle)

This means each palindrome can accommodate at most one character with an odd count. If a character appears an odd number of times, one of those occurrences must be the "center" of some palindrome.

Now, if we need to form k palindromes:

  • We can have at most k characters with odd counts (one per palindrome as the center)
  • All other characters must have even counts so they can form pairs

Here's the key insight: If we count how many characters in our string s appear an odd number of times, this tells us the minimum number of palindromes we must create. Why? Because each character with an odd count needs to have its "extra" occurrence placed as a center somewhere.

For instance, if we have 3 characters appearing odd times, we need at least 3 palindromes to accommodate these odd occurrences as centers.

The solution becomes clear:

  1. Count the frequency of each character in s
  2. Count how many characters have odd frequencies
  3. If this count is ≀ k, we can form k palindromes (we can always split palindromes further if needed)
  4. If this count is > k, it's impossible (not enough palindromes to hold all the odd-count characters)

Also, we need to check if len(s) < k first - we can't form k non-empty strings if we don't have at least k characters total.

Learn more about Greedy patterns.

Solution Approach

The implementation follows directly from our intuition about counting characters with odd frequencies.

Step 1: Check minimum length constraint

First, we check if len(s) < k. If the string has fewer characters than k, it's impossible to create k non-empty palindrome strings, so we immediately return false.

if len(s) < k:
    return False

Step 2: Count character frequencies

We use Python's Counter from the collections module to count the frequency of each character in the string s. This creates a hash table where keys are characters and values are their counts.

cnt = Counter(s)

For example, if s = "aabbbc", then cnt would be {'a': 2, 'b': 3, 'c': 1}.

Step 3: Count characters with odd frequencies

We iterate through all the frequency values and count how many are odd. The expression v & 1 is a bitwise operation that returns 1 if v is odd and 0 if v is even (checking the least significant bit).

sum(v & 1 for v in cnt.values())

This is equivalent to checking v % 2 but using bitwise AND is slightly more efficient.

Step 4: Compare with k

Finally, we check if the number of characters with odd frequencies is at most k. If it is, we can distribute these odd-count characters as centers across our k palindromes, and return true. Otherwise, we return false.

return sum(v & 1 for v in cnt.values()) <= k

Time Complexity: O(n) where n is the length of string s, as we iterate through the string once to count frequencies.

Space Complexity: O(1) or O(26) to be precise, since we're only storing counts for at most 26 lowercase English letters (assuming the input contains only lowercase letters).

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 s = "aabbbc" and k = 2.

Step 1: Check minimum length constraint

  • len(s) = 6 and k = 2
  • Since 6 β‰₯ 2, we can proceed

Step 2: Count character frequencies

  • Count each character in "aabbbc":
    • 'a' appears 2 times
    • 'b' appears 3 times
    • 'c' appears 1 time
  • So cnt = {'a': 2, 'b': 3, 'c': 1}

Step 3: Count characters with odd frequencies

  • Check each frequency:
    • 'a': 2 is even β†’ contributes 0
    • 'b': 3 is odd β†’ contributes 1
    • 'c': 1 is odd β†’ contributes 1
  • Total odd-frequency characters = 1 + 1 = 2

Step 4: Compare with k

  • We have 2 characters with odd frequencies
  • We need to form k = 2 palindromes
  • Since 2 ≀ 2, we return true

Why this works: We can form two palindromes by placing one odd-count character as the center of each:

  • Palindrome 1: "bab" (using one 'b' as center)
  • Palindrome 2: "abca" (using 'c' as center)

Or alternatively:

  • Palindrome 1: "aba" (using one 'b' as center)
  • Palindrome 2: "bcb" (using 'c' as center)

Each palindrome accommodates exactly one character with an odd count as its center, which is why having 2 odd-count characters works perfectly for forming 2 palindromes.

Solution Implementation

1from collections import Counter
2
3class Solution:
4    def canConstruct(self, s: str, k: int) -> bool:
5        # If string length is less than k, we cannot form k palindromes
6        if len(s) < k:
7            return False
8      
9        # Count frequency of each character in the string
10        char_count = Counter(s)
11      
12        # Count how many characters have odd frequency
13        # For a palindrome, at most one character can have odd frequency
14        # With k palindromes, we can have at most k characters with odd frequency
15        odd_freq_count = sum(freq & 1 for freq in char_count.values())
16      
17        # Check if number of odd frequency characters is at most k
18        return odd_freq_count <= k
19
1class Solution {
2    public boolean canConstruct(String s, int k) {
3        // Get the length of the input string
4        int stringLength = s.length();
5      
6        // If string length is less than k, we cannot form k palindromes
7        // (each palindrome needs at least one character)
8        if (stringLength < k) {
9            return false;
10        }
11      
12        // Array to count frequency of each character (26 lowercase letters)
13        int[] characterFrequency = new int[26];
14      
15        // Count the frequency of each character in the string
16        for (int i = 0; i < stringLength; i++) {
17            characterFrequency[s.charAt(i) - 'a']++;
18        }
19      
20        // Count characters with odd frequency
21        // In a palindrome, at most one character can have odd frequency (the middle character)
22        int oddFrequencyCount = 0;
23        for (int frequency : characterFrequency) {
24            // Check if frequency is odd using bitwise AND with 1
25            oddFrequencyCount += frequency & 1;
26        }
27      
28        // We can construct k palindromes if the number of characters with odd frequency
29        // is at most k (each palindrome can accommodate at most one odd-frequency character)
30        return oddFrequencyCount <= k;
31    }
32}
33
1class Solution {
2public:
3    bool canConstruct(string s, int k) {
4        // If string length is less than k, we cannot form k palindromes
5        if (s.size() < k) {
6            return false;
7        }
8      
9        // Count frequency of each character
10        int charFrequency[26] = {0};
11        for (char& ch : s) {
12            charFrequency[ch - 'a']++;
13        }
14      
15        // Count characters with odd frequency
16        int oddFrequencyCount = 0;
17        for (int frequency : charFrequency) {
18            // Check if frequency is odd using bitwise AND
19            if (frequency & 1) {
20                oddFrequencyCount++;
21            }
22        }
23      
24        // We can form k palindromes if the number of characters with odd frequency
25        // is at most k (each palindrome can have at most one character with odd frequency)
26        return oddFrequencyCount <= k;
27    }
28};
29
1/**
2 * Determines if string s can be constructed into k palindromes
3 * @param s - The input string to be divided into palindromes
4 * @param k - The number of palindromes to construct
5 * @returns true if s can be constructed into exactly k palindromes, false otherwise
6 */
7function canConstruct(s: string, k: number): boolean {
8    // Cannot form k palindromes if string length is less than k
9    // (each palindrome needs at least one character)
10    if (s.length < k) {
11        return false;
12    }
13  
14    // Array to count frequency of each letter (26 letters in alphabet)
15    const charFrequency: number[] = new Array(26).fill(0);
16  
17    // Count the frequency of each character in the string
18    for (const char of s) {
19        const charIndex = char.charCodeAt(0) - 'a'.charCodeAt(0);
20        charFrequency[charIndex]++;
21    }
22  
23    // Count characters with odd frequency
24    // In a palindrome, at most one character can have odd frequency (the middle character)
25    let oddFrequencyCount = 0;
26    for (const frequency of charFrequency) {
27        // Use bitwise AND to check if frequency is odd (frequency & 1 returns 1 if odd, 0 if even)
28        oddFrequencyCount += frequency & 1;
29    }
30  
31    // We can form k palindromes if the number of characters with odd frequency
32    // is at most k (each palindrome can have at most one odd-frequency character)
33    return oddFrequencyCount <= k;
34}
35

Time and Space Complexity

The time complexity is O(n), where n is the length of string s. This is because:

  • Creating a Counter object requires iterating through all characters in the string once: O(n)
  • The sum(v & 1 for v in cnt.values()) iterates through the values in the counter, which has at most min(n, 26) entries (since there are only 26 lowercase letters). This takes O(26) = O(1) time in the worst case

The space complexity is O(C), where C is the size of the character set. In this case, C = 26 since we're dealing with lowercase English letters. The Counter object stores at most 26 key-value pairs (one for each unique character that appears in the string), regardless of how long the input string is.

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

Common Pitfalls

Pitfall 1: Forgetting the Upper Bound Check

The Problem: Many developers focus only on checking if there are too many characters with odd frequencies (odd_freq_count <= k) but forget to verify if the string is long enough to form k palindromes in the first place.

Incorrect Implementation:

def canConstruct(self, s: str, k: int) -> bool:
    char_count = Counter(s)
    odd_freq_count = sum(freq & 1 for freq in char_count.values())
    return odd_freq_count <= k  # Missing length check!

Why It Fails: For input s = "ab" and k = 3, this would incorrectly return True because there are only 2 odd-frequency characters (both 'a' and 'b' appear once). However, you cannot create 3 non-empty palindromes from just 2 characters.

The Fix: Always check if len(s) >= k before proceeding with the odd frequency logic:

if len(s) < k:
    return False

Pitfall 2: Misunderstanding the Odd Frequency Constraint

The Problem: Some might think that having odd-frequency characters means the solution is impossible, or they might incorrectly calculate the relationship between odd frequencies and palindrome count.

Incorrect Logic Examples:

# Wrong: Thinking any odd frequency makes it impossible
return all(freq % 2 == 0 for freq in char_count.values())

# Wrong: Checking if odd count equals k exactly
return odd_freq_count == k

Why It Fails:

  • First example: Single-character palindromes are valid (like "a"), so odd frequencies are perfectly fine.
  • Second example: If s = "aabbcc" and k = 2, all characters have even frequency (odd_freq_count = 0), but we can still form 2 palindromes like "abc" and "abc" or "aabbcc" split differently.

The Fix: Remember that each palindrome can accommodate at most one character with odd frequency (as its center). So with k palindromes, you can have at most k characters with odd frequencies:

return odd_freq_count <= k

Pitfall 3: Overcomplicated Distribution Logic

The Problem: Attempting to actually distribute characters into k palindromes or trying to construct the palindromes explicitly.

Overcomplicated Approach:

def canConstruct(self, s: str, k: int) -> bool:
    # Trying to actually build the palindromes
    palindromes = [[] for _ in range(k)]
    char_count = Counter(s)
  
    # Complex distribution logic...
    for char, count in char_count.items():
        # Trying to evenly distribute pairs
        pairs = count // 2
        for i in range(pairs):
            palindromes[i % k].append(char)
            palindromes[i % k].append(char)
        # Handle remaining odd character
        if count % 2 == 1:
            # More complex logic...

Why It's Unnecessary: The problem only asks if it's possible to construct k palindromes, not to actually construct them. The mathematical constraint (odd_freq_count <= k) is sufficient to determine possibility.

The Fix: Stick to the simple counting approach. The beauty of this problem is that you don't need to construct anythingβ€”just verify the constraints are satisfied.

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

The three-steps of Depth First Search are:

  1. Identify states;
  2. Draw the state-space tree;
  3. DFS on the state-space tree.

Recommended Readings

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

Load More