<p>Given the string <code>s</code>, return the size of the longest substring containing each vowel an even number of times. That is, &#39;a&#39;, &#39;e&#39;, &#39;i&#39;, &#39;o&#39;, and &#39;u&#39; must appear an even number of times.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>

<pre>
<strong>Input:</strong> s = &quot;eleetminicoworoep&quot;
<strong>Output:</strong> 13
<strong>Explanation: </strong>The longest substring is &quot;leetminicowor&quot; which contains two each of the vowels: <strong>e</strong>, <strong>i</strong> and <strong>o</strong> and zero of the vowels: <strong>a</strong> and <strong>u</strong>.
</pre>

<p><strong class="example">Example 2:</strong></p>

<pre>
<strong>Input:</strong> s = &quot;leetcodeisgreat&quot;
<strong>Output:</strong> 5
<strong>Explanation:</strong> The longest substring is &quot;leetc&quot; which contains two e&#39;s.
</pre>

<p><strong class="example">Example 3:</strong></p>

<pre>
<strong>Input:</strong> s = &quot;bcbcbc&quot;
<strong>Output:</strong> 6
<strong>Explanation:</strong> In this case, the given string &quot;bcbcbc&quot; is the longest because all vowels: <strong>a</strong>, <strong>e</strong>, <strong>i</strong>, <strong>o</strong> and <strong>u</strong> appear zero times.
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>1 &lt;= s.length &lt;= 5 x 10^5</code></li>
	<li><code>s</code>&nbsp;contains only lowercase English letters.</li>
</ul>

class Solution:
    def findTheLongestSubstring(self, s: str) -> int:
        # left, right = 0, len(s) - 1
        # vowelMap = {
        #     "a": [],
        #     "e": [],
        #     "i": [],
        #     "o": [],
        #     "u": []
        # }
        # substring = s
        # for i in range(len(s)):
        #     if s[i] in vowelMap:
        #         vowelMap[s[i]].append(i)
        # print(vowelMap)
        # swap_left = 0
        # swap_right = 0
        # while left <= right:
        #     potential_subs = []
        #     num_odd = 0
        #     min_left_diff = len(s)
        #     min_right_diff = len(s) # so they get swapped
            
        #     for vowel, indexArr in vowelMap.items():
        #         if not len(indexArr) % 2:
        #             # odd - potential swap
        #             num_odd += 1
        #             potential_subs.extend(indexArr)
        #             # find the potential swaps
        #     if num_odd == 0:
        #         return s[left:right] # no swaps to be made
        #     # now find closest waps - compare min_left and min_right against potential_subs
        #     for index in potential_subs:
        #         if abs(left-index) < min_left_diff:
        #             min_left_diff = abs(left-index)
        #             swap_left = index
        #         if abs(right-index) < min_right_diff:
        #             min_right_diff = abs(right-index)
        #             swap_right = index
        #     print(min_left_diff)
        #     print(min_right_diff)
        #     if min_left_diff < min_right_diff:
        #         left += swap_left
        #     else:
        #         right = swap_right

        # return s[left:right] 
        ### NEETCODE ###
        vowels = "aeiou"

        res = 0
        mask = 0 # keep track of cur state
        # for every mask, map to first index it showed up at
        # default is 0
        mask_to_idx = {0: -1} # ex "xxxx" want to remove prefix
        # with same state. first substr w/ same was empty one.
        # subtract first substr @ -1 --> 3 - -1 = 4

        for i, c in enumerate(s):
            if c in vowels:
                # take exclusive or
                mask = mask ^ 1 + ord(c) - ord('a') # tells us which bit to set in bit mask
                # ex 0000. bitwise or? 0001.
                # we want to keep track of even and odd.
                # 1 --> odd. bitwise or would make it stay as one
                # something else called bitwise exclusive or
                # 0001 ^
                # lower case a --> get ascii val and subtract will get 0
                # set least significant bit of a:
                # 0000 ^ 0000 (zero exclusive or (or XOR) zero)
                # fix - add 1
                # 0000 ^ 0001
            if mask in mask_to_idx:
                # we've alreaady seen it - use current window
                length = i - mask_to_idx[mask] # mask first showed up
                res = max(res, length)
            else:
                # haven't seen it.
                # add to map
                mask_to_idx[mask] = i

        return res
22200