# time O(2N)  space O(1)
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        l, r = 0, 0
        d = {}
        res = 0
        while r < len(s):
            if s[r] not in d:
                d[s[r]] = 1
            else:
                d[s[r]] += 1
            while d[s[r]] > 1:
                d[s[l]] -= 1
                l += 1
            res = max(res,r-l+1)
            r += 1 
        
        return res 

optimize

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        # instead of storing freq, we can store index
        d = {} # ch: idx 
        l = res = 0
        for r,val in enumerate(s):
            if val in d:
                if d[val] >= l :
                    l = d[val] +1
            res = max(res,r-l+1)
            d[val] = r
        return res