This can be solved in O (n) time and space using the "net" values ββcomputed by this answer in combination with the following observation:
- The substring s [i .. j] has the same number of consonants and vowels if and only if net [1 .. i-1] = net [1, j], where net [i .. j] is the sum " pure "values ββ(1 for the vowel, -1 for the consonant) for each character between positions i and j inclusively.
To verify this, note that the condition indicating that the substring s [i .. j] is the kind we are looking for is that
net[i .. j] = 0.
Adding a network [1 .. i-1] to both sides of this equation gives
net[1 .. i-1] + net[i .. j] = net[1 .. i-1]
with LHS and then simplifying only
net[1 .. j] = net[1 .. i-1]
Algorithm
This means that we can create a table containing two records (visible first position and last position) for each possible different value that we could get when we calculate the current amount of pure values. This current total amount can have a value of -n (if each character is consonant) or higher than n (if each character is a vowel), so the total is no more than 2n + 1 of such sums, so we will need a lot in our table lines. Then we go through the line from left to right, calculating the current total network value and update the pair in the table that corresponds to the current total, noticing when this update creates a new substring of maximum length. In pseudocode with zero array indices and using separate arrays to store elements in each pair:
- Create 2 arrays of length 2n + 1, first [] and last [], initially containing all -2s, except for the first [n], which is -1. (You must use -2 as a sentinel, since -1 is actually a valid value!)
- Set bestFirst = bestLast = bestLen = -1.
- Set the current value t = n. (n "means" 0, using this offset means that we can use the current value directly as a non-negative index in arrays without having to repeatedly add the offset to it.)
- For i from 0 to n-1:
- If s [i] is a vowel, increment t; otherwise, decrease t.
- If the first [t] is -2:
- Otherwise:
- Set the last [t] = i.
- If the last [t] is the first [t]> bestLen:
- Set bestLen = last [t] - first [t].
- Set bestFirst = first [t] + 1.
- Set bestLast = last [t].
The maximum length range will be returned (bestFirst, bestLast), or if no such range exists, these variables will be -1.
I remember that I saw this solution, or very similar to it, somewhere in SO some time ago - if anyone can find it, I will be happy to contact him.
source share