Problem
You are given a string s
. An awesome substring is a non-empty substring of s
such that we can make any number of swaps in order to make it a palindrome.
Return the length of the maximum length awesome substring of s
.
Examples
Example 1:
Input: s = "3242415"
Output: 5
Explanation: "24241" is the longest awesome substring, we can form the palindrome "24142" with some swaps.
Example 2:
Input: s = "12345678"
Output: 1
Example 3:
Input: s = "213123"
Output: 6
Explanation: "213123" is the longest awesome substring, we can form the palindrome "231132" with some swaps.
Solution
Method 1 - Using bitmask and hashmap
Here is the approach:
To identify the length of the maximum awesome
substring that can be made a palindrome by swapping characters in s
, we need to leverage the properties of palindromes:
- Palindrome Properties:
- A string is a palindrome if each character appears an even number of times, except for at most one character which can appear an odd number of times.
- Use Bitmasking:
- Use a bitmask to represent the parity (odd/even) of character counts. This way, each bit in the bitmask corresponds to a character (
a
toz
), indicating whether the character’s count is odd or even. - Compute the state (bitmask) as we iterate through the string. This helps track the parity of character counts up to each position.
- Use a bitmask to represent the parity (odd/even) of character counts. This way, each bit in the bitmask corresponds to a character (
- HashMap for Previous States:
- Use a HashMap to store the first occurrence of each bitmask. This helps in quickly calculating the maximum length of substrings with specific properties.
- If we encounter the same bitmask again, it means the characters in between can form a palindrome.
- Check for Single Odd Character:
- Besides checking for exact bitmask parity, also check for each bit deviation to allow for one odd character (using
mask ^ (1 << i)
).
- Besides checking for exact bitmask parity, also check for each bit deviation to allow for one odd character (using
Code
Java
public class Solution {
public int maxLengthAwesomeSubstring(String s) {
Map<Integer, Integer> map = new HashMap<>();
int mask = 0, ans = 0;
map.put(0, -1);
for (int i = 0; i < s.length(); i++) {
mask ^= 1 << (s.charAt(i) - 'a');
if (map.containsKey(mask)) {
ans = Math.max(ans, i - map.get(mask));
} else {
map.put(mask, i);
}
for (int j = 0; j < 26; j++) {
int temp_mask = mask ^ (1 << j);
if (map.containsKey(temp_mask)) {
ans = Math.max(ans, i - map.get(temp_mask));
}
}
}
return ans;
}
}
Python
class Solution:
def maxLengthAwesomeSubstring(self, s: str) -> int:
map = {0: -1}
mask = 0
ans = 0
for i, char in enumerate(s):
mask ^= 1 << (ord(char) - ord('a'))
if mask in map:
ans = max(ans, i - map[mask])
else:
map[mask] = i
for j in range(26):
temp_mask = mask ^ (1 << j)
if temp_mask in map:
ans = max(ans, i - map[temp_mask])
return ans
Complexity
- ⏰ Time complexity:
O(n)
, wheren
is the length of the strings
. Each character is processed once, updating and checking the bitmask. - 🧺 Space complexity:
O(1)
for the bitmask and auxiliary variables, but the HashMap can grow up toO(n)
in the worst case.