class Solution:
def longestAwesome(self, s: str) -> int:
pos = {0: -1}
mask = 0
res = 0
for i, ch in enumerate(s):
digit = int(ch)
mask ^= (1 << digit)
if mask in pos:
res = max(res, i - pos[mask])
else:
pos[mask] = i
for d in range(10):
test_mask = mask ^ (1 << d)
if test_mask in pos:
res = max(res, i - pos[test_mask])
return res
class Solution {
public:
int longestAwesome(string s) {
unordered_map<int, int> pos;
pos[0] = -1;
int mask = 0, res = 0;
for (int i = 0; i < s.size(); ++i) {
int digit = s[i] - '0';
mask ^= (1 << digit);
if (pos.count(mask))
res = max(res, i - pos[mask]);
else
pos[mask] = i;
for (int d = 0; d < 10; ++d) {
int test_mask = mask ^ (1 << d);
if (pos.count(test_mask))
res = max(res, i - pos[test_mask]);
}
}
return res;
}
};
import java.util.*;
class Solution {
public int longestAwesome(String s) {
Map<Integer, Integer> pos = new HashMap<>();
pos.put(0, -1);
int mask = 0, res = 0;
for (int i = 0; i < s.length(); ++i) {
int digit = s.charAt(i) - '0';
mask ^= (1 << digit);
if (pos.containsKey(mask))
res = Math.max(res, i - pos.get(mask));
else
pos.put(mask, i);
for (int d = 0; d < 10; ++d) {
int testMask = mask ^ (1 << d);
if (pos.containsKey(testMask))
res = Math.max(res, i - pos.get(testMask));
}
}
return res;
}
}
var longestAwesome = function(s) {
let pos = new Map();
pos.set(0, -1);
let mask = 0, res = 0;
for (let i = 0; i < s.length; ++i) {
let digit = s.charCodeAt(i) - '0'.charCodeAt(0);
mask ^= (1 << digit);
if (pos.has(mask))
res = Math.max(res, i - pos.get(mask));
else
pos.set(mask, i);
for (let d = 0; d < 10; ++d) {
let testMask = mask ^ (1 << d);
if (pos.has(testMask))
res = Math.max(res, i - pos.get(testMask));
}
}
return res;
};
You are given a string s
consisting only of digits ('0' to '9'). A substring of s
is called awesome if, after rearranging its characters, it becomes a palindrome (reads the same forwards and backwards).
Your task is to find the length of the longest awesome substring in s
.
s
.Constraints:
s.length
≤ 105s
consists only of digits ('0' to '9').The core challenge is to efficiently check, for every substring, whether it can be rearranged into a palindrome.
At first, one might consider checking all possible substrings and, for each, counting digit frequencies to see if at most one digit occurs an odd number of times (which is the necessary and sufficient condition for a string to be rearranged into a palindrome). However, this brute-force approach is too slow for large strings.
To optimize, we need a way to quickly determine, for any substring, if its digit counts meet the palindrome condition. This leads us to use prefix masks (bitmasks) that encode the parity (odd/even) of each digit's count up to each position. If two prefixes have the same mask, the substring between them has all even counts. If they differ by only one bit, the substring has exactly one odd count, which is also allowed for a palindrome.
So, the problem becomes one of finding the farthest pair of indices with matching or single-bit-differing masks, which can be done efficiently with hashing.
Let's break down the algorithm step by step:
pos
) that records the first index where each mask occurs.This approach ensures that each mask is processed in constant time, making the solution efficient enough for large input sizes.
Let's use the input s = "3242415"
as an example.
mask = 0
, pos = {0: -1}
, res = 0
.
The output for this example is 5.
Thus, the optimized solution is very efficient and suitable for large inputs.
To solve the "Find Longest Awesome Substring" problem, we use a bitmask to track the parity of digit counts and a hash map to remember the earliest occurrence of each mask. By checking for matching masks and masks differing by one bit, we can efficiently determine the longest substring that can be rearranged into a palindrome. This approach leverages bit manipulation and prefix properties for a linear time solution, making it both elegant and highly efficient.