A wonderful string is a string where at most one letter appears an odd number of times.
"ccjjc"
and "abab"
are wonderful, but "ab"
is not.Given a string word
that consists of the first ten lowercase English letters ('a'
through 'j'
), return the number of wonderful non-empty substrings in word
. If the same substring appears multiple times in word
, then count each occurrence separately.
A substring is a contiguous sequence of characters in a string.
Example 1:
Input: word = "aba" Output: 4 Explanation: The four wonderful substrings are underlined below: - "aba" -> "a" - "aba" -> "b" - "aba" -> "a" - "aba" -> "aba"
Example 2:
Input: word = "aabb" Output: 9 Explanation: The nine wonderful substrings are underlined below: - "aabb" -> "a" - "aabb" -> "aa" - "aabb" -> "aab" - "aabb" -> "aabb" - "aabb" -> "a" - "aabb" -> "abb" - "aabb" -> "b" - "aabb" -> "bb" - "aabb" -> "b"
Example 3:
Input: word = "he" Output: 2 Explanation: The two wonderful substrings are underlined below: - "he" -> "h" - "he" -> "e"
Constraints:
1 <= word.length <= 105
word
consists of lowercase English letters from 'a'
to 'j'
.This problem leverages bit manipulation and prefix sums to efficiently count wonderful substrings. A "wonderful" substring is defined as a substring where at most one character appears an odd number of times.
Core Idea:
We use a 10-bit integer (st
) to represent the parity (even or odd) of the counts of each of the ten characters ('a' to 'j'). Each bit corresponds to a character: if the bit is set, the character count is odd; otherwise, it's even.
We iterate through the string, updating st
as we encounter each character. For each prefix of the string, we check how many previously seen prefixes have a bitmask that differs from the current prefix's bitmask by at most one bit (meaning at most one character has a different parity). This difference indicates a wonderful substring.
Algorithm:
Initialization: Create a cnt
array (hash map or array) to store the counts of each bitmask encountered. Initialize cnt[0]
to 1 because the empty substring has all even counts. st
(state) is initialized to 0. ans
(answer) is initialized to 0.
Iteration: Iterate through the characters of the word
.
Update State: For each character, update st
by XORing it with 1 << (c - 'a')
. This flips the bit corresponding to the character, reflecting the change in parity.
Count Wonderful Substrings:
cnt[st]
to ans
. This counts substrings ending at the current position with the same parity as the current prefix.cnt[st ^ (1 << i)]
for i
from 0 to 9 to ans
. This counts substrings where exactly one character has different parity compared to the current prefix.Update Count: Increment cnt[st]
to record the occurrence of the current bitmask.
Return: Return ans
, the total count of wonderful substrings.
Time Complexity: O(N), where N is the length of the word. We iterate through the string once. The inner loop iterates 10 times in each iteration of the outer loop, contributing a constant factor.
Space Complexity: O(210) = O(1), because the cnt
array has a fixed size of 1024 (210). The space used is constant, regardless of the input size.
Example Walkthrough (word = "aba"):
Initially, cnt[0] = 1
, st = 0
, ans = 0
.
'a': st
becomes 1 << 0 = 1
. ans
+= cnt[1]
(0) + cnt[0]
(1) + ... = 1. cnt[1] = 1
.
'b': st
becomes 1 ^ (1 << 1) = 3
. ans
+= cnt[3]
(0) + cnt[2]
(0) + cnt[1]
(1) + cnt[0]
(1) = 2. cnt[3] = 1
.
'a': st
becomes 3 ^ (1 << 0) = 2
. ans
+= cnt[2]
(0) + cnt[3]
(1) + cnt[1]
(1) + cnt[0]
(1) = 4. cnt[2] = 1
.
ans
(4) is returned.
The code provided in various languages implements this algorithm efficiently. The use of bit manipulation significantly optimizes the solution's performance.