Leetcode 409. Longest Palindrome

Problem Explanation

This problem requires you to find the length of the longest palindrome that can be built with the given letters. A palindrome is a string that reads the same way forwards as it does backwards. Letters are case-sensitive in this problem, i.e., 'A' and 'a' are considered different characters.

Let's walk through an example where the input string is "abccccdd".

The unique characters in the input string are a, b, c and d. The frequency count of each character is: a-1, b-1, c-4, d-2

If we arrange these characters in a palindrome, we can have 'd' and 'c' on either side of the palindrome like "ddcc....ccdd" since they occur an even number of times, 'a' and 'b' can only be used once in the middle like "ddcca....bccdd". Therefore, the length of the longest palindrome that can be built is 2+4+1=7.

Solution Approach

The solution uses simple counts logic and bitwise AND operator for efficiency in a 2-pass algorithm. It makes use of an integer array 'count' with ASCII size to hold the frequencies of each character in the string.

  • In the first pass, it counts the frequency of each character in the string.
  • In the second pass, it adds up the counts to 'ans', but if the count is odd, it subtracts 1 before adding.
  • After it has traversed through all the counts, it checks if there is any character with an odd count. If so, it increments 'ans' by 1, else it returns 'ans'.

The reason this solution works is because a palindrome can be formed by placing characters with even counts on either side and at most one character with an odd count in the middle.

C++ Solution

1
2cpp
3class Solution {
4 public:
5  int longestPalindrome(string s) {
6    int ans = 0;
7    vector<int> count(128);
8    for (const char c : s)
9      ++count[c];
10    for (const int c : count)
11      ans += c % 2 == 0 ? c : c - 1;
12    const bool hasOddCount =
13        any_of(begin(count), end(count), [](int c) { return c & 1; });
14    return ans + hasOddCount;
15  }
16};

Java Solution

1
2java
3class Solution {
4    public int longestPalindrome(String s) {
5        int[] count = new int[128];
6        int ans = 0;
7        for (char c : s.toCharArray())
8            count[c]++;
9        for (int c: count){
10            ans += c % 2 == 0 ? c : c - 1;
11        }
12        for (int c: count){
13            if ( c % 2 == 1){
14                ans++;
15                break;
16            }
17        }
18        return ans;
19    }
20}

Python Solution

1
2python
3class Solution:
4    def longestPalindrome(self, s: str) -> int:
5        count = [0]*128
6        ans = 0
7        for c in s:
8            count[ord(c)]+=1
9        for c in count:
10            ans += c if c % 2 == 0 else c - 1
11        if any( c % 2 == 1 for c in count):
12            ans+=1
13        return ans

JavaScript Solution

1
2javascript
3var longestPalindrome = function(s) {
4    let count = new Array(128).fill(0);
5    let ans = 0;
6    for (let c of s)
7        count[c.charCodeAt(0)]++;
8    for (let c of count)
9        ans += c % 2 == 0 ? c : c - 1;
10    if(count.some((c) => c & 1))
11        ans++;
12    return ans;
13};

C# Solution

1
2csharp
3public class Solution {
4    public int LongestPalindrome(string s) {
5        int[] count = new int[128];
6        int ans = 0;
7        foreach (char c in s)
8            count[c]++;
9        foreach(int c in count)
10            ans += c % 2 == 0 ? c : c - 1;
11        if (count.Any(c => c % 2 == 1))
12            ans++;
13        return ans;
14    }
15}

These solutions run in O(n) time complexity where n is the length of the input string, since we need to count the frequency for each character. They also require O(1) extra space, only for the count array. This problem gives us a good sense of count and bitwise manipulations, and since it is easy to understand, it is often used in coding interviews.# Swift Solution

1
2swift
3class Solution {
4    func longestPalindrome(_ s: String) -> Int {
5        var count = [Character: Int]()
6        var ans = 0
7        for char in s {
8            if let cnt = count[char] {
9                count[char] = cnt + 1
10            } else {
11                count[char] = 1
12            }
13        }
14        for (_, value) in count {
15            ans += value % 2 == 0 ? value : value - 1
16        }
17        if count.contains(where: { $1 & 1 == 1 }) {
18            ans += 1
19        }
20        return ans
21    }
22}

In Swift, to solve this problem, you would use a dictionary instead of an array to store the counts of characters, since Swift doesn't have an equivalent to the ASCII-based array index tracking like other languages. Everything else, including the idea of getting the count of each character and accounting for palindromes of odd length, remains the same.

Remember, a key takeaway is understanding how to analyze the problem and come up with a solution based on simple counts logic. We learn about string parsing, hash tables or dictionaries, and bitwise operations in this problem.

Additionally, we learn about the ASCII values of characters and how we can use them to create a unique indexing system for each character.

Each of these implementations provide an efficient solution to the problem in their respective languages, and they are great learning due to their high runtime and space efficiency. Understanding these solutions deepens our grasp of the data structures and programming languages we use to solve algorithmic problems. Hence it is a common problem given in coding interviews to test problem-solving capabilities.


Got a question? Ask the Teaching Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.


TA 👨‍🏫