[Easy] 409. Longest Palindrome
Given a string s which consists of lowercase or uppercase letters, return the length of the longest palindrome that can be built with those letters.
Letters are case sensitive, for example, "Aa" is not considered a palindrome here.
Note: You can use any characters from the string, and you can rearrange them arbitrarily.
Examples
Example 1:
Input: s = "abccccdd"
Output: 7
Explanation: One longest palindrome that can be built is "dccaccd", whose length is 7.
Example 2:
Input: s = "a"
Output: 1
Explanation: The longest palindrome is "a".
Example 3:
Input: s = "bb"
Output: 2
Explanation: The longest palindrome is "bb".
Constraints
1 <= s.length <= 2000sconsists of lowercase and/or uppercase English letters only.
Thinking Process
- Palindrome Structure: Symmetric pairs + optional center
- Greedy works when local optimal choices lead to global optimum.
- Often sort first to make the greedy choice obvious.
- Prove or sanity-check: would swapping two choices ever help?
Common Approaches
Typical techniques for this pattern:
| Approach | Time | Space | Notes |
|---|---|---|---|
| Sort + greedy (this problem) | O(n log n) | O(1) | Interval scheduling, assignment |
| Local greedy choice | O(n) | O(1) | Jump game, gas station |
| Greedy + heap | O(n log n) | O(n) | Merge streams, room allocation |
| Exchange argument | O(n) | O(1) | Prove greedy choice is safe |
Solution
class Solution:
def longestPalindrome(self, s):
maskl = 0 # [a - z]
maskU = 0 # [A - Z]
rtn = 0
for c in s:
if 'a' <= c and c <= 'z':
bit = 1 << (ord(c) - ord('a'))
if maskl & bit:
rtn += 2
maskl ^= bit
else:
maskl ^= bit
else:
bit = 1 << (ord(c) - ord('A'))
if maskU & bit:
rtn += 2
maskU ^= bit
else:
maskU ^= bit
return rtn + 1 if (maskl or maskU) else rtn
Solution Explanation
Approach: Sort + greedy (this problem)
Key idea: 1. Palindrome Structure: Symmetric pairs + optional center
How the code works:
- Palindrome Structure: Symmetric pairs + optional center
- Greedy works when local optimal choices lead to global optimum.
- Often sort first to make the greedy choice obvious.
- Prove or sanity-check: would swapping two choices ever help?
Walkthrough — input s = "abccccdd", expected output 7:
One longest palindrome that can be built is “dccaccd”, whose length is 7.
Common Mistakes
- Single character:
s = "a"→ return 1 - All pairs:
s = "bb"→ return 2 - All same character:
s = "aaaa"→ return 4 - Mixed case:
s = "Aa"→ return 1 (case sensitive) - No pairs:
s = "abc"→ return 1 (one character in center) -
All unique:
s = "abcdef"→ return 1 - Case sensitivity: Treating ‘A’ and ‘a’ as same
- Center placement: Forgetting to add 1 when odd counts exist
- Pair counting: Incorrectly counting pairs
- Bit manipulation: Off-by-one errors in bit shifting
- Empty string: Not handling edge case (but constraints guarantee length ≥ 1)
Related Problems
- LC 5: Longest Palindromic Substring - Find longest palindrome substring
- LC 125: Valid Palindrome - Check if string is palindrome
- LC 131: Palindrome Partitioning - Partition into palindromes
- LC 647: Palindromic Substrings - Count palindromic substrings
- LC 1177: Can Make Palindrome from Substring - Check if substring can form palindrome
- LC 1400: Construct K Palindrome Strings - Construct multiple palindromes
Key Takeaways
- Palindrome Structure: Symmetric pairs + optional center
- Pair Counting: Each pair contributes 2 to length
- Odd Handling: At most one character can be in center
- Bit Manipulation: Efficient way to track odd/even counts
- Case Sensitivity: Must handle uppercase and lowercase separately
References
- LC 409: Longest Palindrome on LeetCode
- LeetCode Discuss — LC 409: Longest Palindrome
- LeetCode Editorial (may require premium)