<p>You are given a string <code>text</code>. You can swap two of the characters in the <code>text</code>.</p>

<p>Return <em>the length of the longest substring with repeated characters</em>.</p>

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

<pre>
<strong>Input:</strong> text = &quot;ababa&quot;
<strong>Output:</strong> 3
<strong>Explanation:</strong> We can swap the first &#39;b&#39; with the last &#39;a&#39;, or the last &#39;b&#39; with the first &#39;a&#39;. Then, the longest repeated character substring is &quot;aaa&quot; with length 3.
</pre>

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

<pre>
<strong>Input:</strong> text = &quot;aaabaaa&quot;
<strong>Output:</strong> 6
<strong>Explanation:</strong> Swap &#39;b&#39; with the last &#39;a&#39; (or the first &#39;a&#39;), and we get longest repeated character substring &quot;aaaaaa&quot; with length 6.
</pre>

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

<pre>
<strong>Input:</strong> text = &quot;aaaaa&quot;
<strong>Output:</strong> 5
<strong>Explanation:</strong> No need to swap, longest repeated character substring is &quot;aaaaa&quot; with length is 5.
</pre>

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

<ul>
	<li><code>1 &lt;= text.length &lt;= 2 * 10<sup>4</sup></code></li>
	<li><code>text</code> consist of lowercase English characters only.</li>
</ul>

# notes

# looking for length of longest substring with repeated chars

# you can swap two chars in the string

# ababa
# aaabb -> 3

# is repeating, cur char = a
# a a a b a a a
# ^
#         ^

# when encoutering you first break:
#     you always would want to swap with the match behind you? or farthest away match, if one is >= your lead pointer or < your tail pointer
#     then just keep counting

# when encountering another break, just swap back and start over
# move left pointer to point of first swap

# a a a b c d
# ^
#         ^

# a b a a a a c a a c
#     ^
#               ^

#   a   b
# a b a a c
# ^
#       ^

# a c a a a a c a a a a
#     ^
#                      ^

# a a a c c c c c
#       ^
#         ^

# 
# 0 1 2 3 4 5 6 7 8 9 10
# b b a b a b a a a a
#     ^
#         ^


# 0 1 2 3 4 5
# a b c d e f
# ^
#     ^

# "ababa" 3
# "aaabaaa" 6
# "aaaaa" 5
# "bbababaaaa" 6
# "abcdef" 1

class Solution:
    def maxRepOpt1(self, text: str) -> int:
        def helper(text):
            char_locs = {}
            for i, c in enumerate(text):
                if c not in char_locs:
                    char_locs[c] = []
                char_locs[c].append(i)

            chars = [c for c in text]

            right = 1
            left = 0
            max_size = 0
            where_swap_occured = None
            old_swap_loc = None
            while right < len(chars) + 1:
                cur_char = chars[left]
                next_char = chars[right - 1]

                # if char is matching, do nothing, just continue

                # if char is not matching, see if we can swap                
                if next_char != cur_char:

                    # get possible swap location, None if no valid swap
                    swap_loc = Solution._get_swap_loc(left, right, char_locs, chars)
                    if where_swap_occured is None and swap_loc is not None:
                        # if we havent swapped yet, and there's a valid swap loc, do the swap
                        chars[right - 1], chars[swap_loc] = chars[swap_loc], chars[right - 1]

                        # save our swaps for later so we can undo it
                        old_swap_loc = swap_loc
                        where_swap_occured = right - 1

                    else:
                        # can't swap, let's clean up
                        if right - left - 1 > max_size:
                            # record the current size
                            max_size = right - left - 1

                        # undo the swap and move up left pointer
                        if where_swap_occured is not None:
                            chars[where_swap_occured], chars[old_swap_loc] = chars[old_swap_loc], chars[where_swap_occured]
                            left = where_swap_occured
                            right = left
                        else:
                            left = right - 1
                            right = left

                        old_swap_loc = None
                        where_swap_occured = None

                right += 1

            if right - left - 1 > max_size:
                max_size = right - left - 1

            return max_size
        return max(helper(text), helper(text[::-1]))
    
    
    def _get_swap_loc(left: int, right: int, char_locs: dict[str, list[int]], chars: list[str]) -> int | None:
        # return char to the left of left, or farthest to the right of right if it's outside of right
        # looking for text[left]
        
        char = chars[left]
        left_most = char_locs[char][0]
        right_most = char_locs[char][-1]
        
        if left_most < left:
            return left_most
        if right_most >= right:
            return right_most
        
        return None
            
        
17700