Understanding the Extraordinary Substrings Problem

The HackerRank Extraordinary Substrings problem asks you to count all substrings of a given string where every character that appears in the substring also appears at least as many times as its alphabetical index, with a=1, b=2, c=3, and so on. At first glance, the brute force approach seems obvious — generate every substring, check each one, and count the valid ones. That approach is O(n^3) or O(n^4) depending on your implementation, and it fails immediately on any reasonably sized input. I ran into this problem last year while preparing for an interview cycle, and the edge case that got me was strings containing characters with zero or near-zero valid windows. Specifically, a string like "abcd" where no valid extraordinary substring exists beyond individual characters under strict frequency constraints. The naive approach would waste enormous cycles checking substrings that will always fail, so recognizing early termination points became critical.

Extraordinary Substrings Hackerrank Solution

The Brute Force Approach (and Why It Fails)

For reference, the brute force solution iterates over every possible start index i, every possible end index j where j is greater than or equal to i, extracts the substring, counts character frequencies, and checks whether each character's frequency meets or exceeds its alphabetical position value. Here is a Python implementation that will pass very small test cases but time out on anything larger: The inner loop runs n(n+1)/2 times, and each frequency check scans at most 26 characters. For a string of length 100, this is fine. For length 1000, it is already struggling. The time limit on HackerRank for this problem is typically generous enough for O(n^2) solutions but unforgiving for anything worse. The key insight is that you do not need to recount frequencies from scratch for every substring. When you extend a substring by one character, you only update a single frequency count. When you move the start pointer forward, you decrement a single count. This brings the complexity down to O(n^2) with a small constant factor, which is the target complexity for this problem.

Here is the optimized solution:

Get the Full Details

The World's Most Extraordinary Homes - Wikipedia
The World's Most Extraordinary Homes - Wikipedia
```python def extraordinary_substrings(s): count = 0 n = len(s) for i in range(n): freq = {} for j in range(i, n): char = s[j] freq[char] = freq.get(char, 0) + 1 required = ord(char) - ord('a') + 1 if freq[char] >= required: is_extraordinary = True for c, f in freq.items(): req = ord(c) - ord('a') + 1 if f < req: is_extraordinary = False break if is_extraordinary: count += 1 return count ```

The difference from the brute force version is subtle but meaningful. We maintain a running frequency dictionary and only validate the extraordinary condition when the newly added character satisfies its own threshold. This pruning avoids unnecessary full-check passes in many cases. The most common pitfall is not handling the character 'z' correctly. Its required frequency is 26, which means a valid substring containing 'z' must have at least 26 occurrences of 'z' alone. In practice, this makes any extraordinary substring containing 'z' extremely long, and most test cases with 'z' in the string will simply have zero valid substrings unless the string is intentionally constructed. Another edge case is single-character substrings. The character 'a' requires a frequency of 1, so any substring consisting solely of 'a' is automatically extraordinary. Characters 'b' through 'z' require 2 or more occurrences, meaning a single-character substring of any letter other than 'a' is never extraordinary. My personal gotcha moment was forgetting this rule and incorrectly counting a substring of length 1 containing 'b' as valid in a test case.

A third issue is empty strings or strings with no lowercase English letters. HackerRank typically constrains input to lowercase English letters, but if your code receives unexpected characters, the ord() calculation will produce incorrect required values. Adding a validation check at the top of your function is cheap insurance:

```python if not s or not s.islower() or not s.isalpha(): return 0 ```

Performance Characteristics

For a string of length n, the algorithm performs exactly n(n+1)/2 iterations of the inner loop. In the worst case, where every character is 'a', the frequency check inside the inner loop runs fully for each iteration because all previously added characters also need verification. This gives a worst-case of roughly 26 * n(n+1)/2 operations, which for n=500 is around 3.25 million operations — well within typical time limits of 1 to 2 seconds on HackerRank. However, there is a practical ceiling. If the input string approaches or exceeds length 2000, the O(n^2) approach will start timing out. I encountered a test case with n=2000 that produced a Time Limit Exceeded verdict on my first submission, even though the logic was correct. The workaround was to switch to C++ for the same algorithmic approach, since the constant factor difference between Python and C++ is significant enough to clear the time limit. This is not a solution to the algorithmic problem itself but rather a pragmatic reality of HackerRank's judging infrastructure.

The Extraordinary Journey of the Fakir - Wikipedia
The Extraordinary Journey of the Fakir - Wikipedia

Why There Is No Clean O(n) Solution

Some people try to reduce this to a sliding window with two pointers that only moves forward, similar to the classic "longest substring with at most K distinct characters" problem. This does not work here because the extraordinary condition is non-monotonic in a way that prevents simple two-pointer shrinking. Adding a character can make a valid substring invalid, and removing a character from the left can also invalidate a previously valid substring. The state does not degrade predictably as you expand or contract the window, so the standard two-pointer optimization collapses. This means O(n^2) is likely the best you can do for a general solution, and it is the intended complexity for this problem. Any approach claiming O(n) or O(n log n) either contains a logical error or only works for restricted subsets of inputs.

Complete Working Solution

```python def extraordinary_substrings(s): if not s or not s.islower() or not s.isalpha(): return 0 count = 0 n = len(s) for i in range(n): freq = {} for j in range(i, n): char = s[j] freq[char] = freq.get(char, 0) + 1 required = ord(char) - ord('a') + 1 if freq[char] >= required: is_extraordinary = True for c, f in freq.items(): req = ord(c) - ord('a') + 1 if f < req: is_extraordinary = False break if is_extraordinary: count += 1 return count ```

The function takes a single string argument and returns an integer representing the count of extraordinary substrings. Input is read from standard input in the HackerRank template, and the result is printed to standard output. The solution handles all edge cases discussed above and runs within acceptable time limits for inputs up to approximately n=1000 in Python and n=2000 in compiled languages.