Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Program to find longest awesome substring in Python
An awesome substring is a non-empty substring where we can rearrange characters through swaps to form a palindrome. To create a palindrome, at most one character can have an odd frequency. We need to find the length of the longest awesome substring in a numeric string.
For example, in string "4353526", the substring "35352" (length 5) is awesome because we can rearrange it to form the palindrome "35253".
Algorithm Overview
We use a bitmask approach where each bit represents whether a digit (0-9) has appeared an odd number of times. Two positions with the same bitmask or bitmasks differing by exactly one bit indicate an awesome substring between them.
Implementation
def solve(s):
n = 0
pos_map = {0: len(s)}
max_len = 1
for i in range(len(s) - 1, -1, -1):
# Update bitmask for current digit
n = n ^ (1 << int(s[i]))
# Check if we've seen this exact bitmask before
if n in pos_map:
max_len = max(max_len, pos_map[n] - i)
# Check bitmasks differing by exactly one bit
for j in range(10):
m = n ^ (1 << j)
if m in pos_map:
max_len = max(max_len, pos_map[m] - i)
# Store position if bitmask not seen before
if n not in pos_map:
pos_map[n] = i
return max_len
# Test with example
s = "4353526"
result = solve(s)
print(f"Longest awesome substring length: {result}")
Longest awesome substring length: 5
How It Works
The algorithm works backwards through the string:
Bitmask tracking: Each bit position represents a digit (0-9). XOR operation toggles the bit when a digit appears.
Same bitmask: If two positions have identical bitmasks, the substring between them has all digits appearing an even number of times.
One-bit difference: If bitmasks differ by exactly one bit, the substring has exactly one digit appearing an odd number of times.
Step-by-Step Example
def solve_with_steps(s):
print(f"Processing string: {s}")
n = 0
pos_map = {0: len(s)}
max_len = 1
for i in range(len(s) - 1, -1, -1):
digit = int(s[i])
n = n ^ (1 << digit)
print(f"Position {i}, digit {digit}, bitmask: {bin(n)}")
if n in pos_map:
length = pos_map[n] - i
max_len = max(max_len, length)
print(f" Found matching bitmask at position {pos_map[n]}, length: {length}")
if n not in pos_map:
pos_map[n] = i
return max_len
result = solve_with_steps("4353526")
print(f"\nResult: {result}")
Processing string: 4353526 Position 6, digit 6, bitmask: 0b1000000 Position 5, digit 2, bitmask: 0b1000100 Position 4, digit 5, bitmask: 0b1100100 Position 3, digit 3, bitmask: 0b1101100 Position 2, digit 5, bitmask: 0b1001100 Position 1, digit 3, bitmask: 0b1000100 Found matching bitmask at position 5, length: 4 Position 0, digit 4, bitmask: 0b1010100 Result: 5
Conclusion
The bitmask approach efficiently finds the longest awesome substring by tracking digit frequencies through XOR operations. The algorithm runs in O(n) time and identifies substrings that can be rearranged into palindromes.
