# 3. Longest Substring Without Repeating Characters

**<font color=red>难度: Medium</font>**

## 刷题内容

> 原题连接

* https://leetcode.com/problems/longest-substring-without-repeating-characters/description/

> 内容描述

```

Given a string, find the length of the longest substring without repeating characters.

Example 1:

Input: "abcabcbb"
Output: 3 
Explanation: The answer is "abc", with the length of 3. 
Example 2:

Input: "bbbbb"
Output: 1
Explanation: The answer is "b", with the length of 1.
Example 3:

Input: "pwwkew"
Output: 3
Explanation: The answer is "wke", with the length of 3. 
             Note that the answer must be a substring, "pwke" is a subsequence and not a substring.
```

## 解题方案

> 思路 1
******- 时间复杂度: O(N)******- 空间复杂度: O(N)******

slide window, beats 67.09%

```python
class Solution:
    def lengthOfLongestSubstring(self, s):
        """
        :type s: str
        :rtype: int
        """
        if not s or len(s) == 0:
            return 0
        
        l, r = 0, 0
        res, lookup = 0, set()
        while l < len(s) and r < len(s):
            if s[r] not in lookup:
                lookup.add(s[r])
                res = max(res, r-l+1)
                r += 1
            else:
                lookup.discard(s[l])
                l += 1
        return res
```

> 思路 2
******- 时间复杂度: O(N)******- 空间复杂度: O(N)******

思路

粗一看是 dp，细一看是 greedy

我们先从第一个字符开始，只要碰到已经出现过的字符我们就必须从之前出现该字符的index开始重新往后看。

例如‘xyzxlkjh’，当看到第二个‘x’时我们就应该从y开始重新往后看了。

那么怎么判断字符已经出现过了呢？我们使用一个hashmap，将每一个已经阅读过的字符作为键，而它的值就是它在原字符串中的index，如果我们现在的字符不在hashmap里面我们就把它加进hashmap中去，因此，只要目前的这个字符在该hashmap中的值大于等于了这一轮字符串的首字符，就说明它已经出现过了，我们就将首字符的index加1，即从后一位又重新开始读，然后比较目前的子串长度与之前的最大长度，取大者。

### 程序变量解释

- res 代表目前最大子串的长度
- start 是这一轮未重复子串首字母的 index
- maps 放置每一个字符的 index，如果 maps.get(s[i], -1) 大于等于 start 的话，就说明字符重复了，此时就要重置 res 和 start 的值了，


beats 74.35%

```python
class Solution:
    def lengthOfLongestSubstring(self, s):
        """
        :type s: str
        :rtype: int
        """
        res, start, n = 0, 0, len(s)
        maps = {}
        for i in range(n):
            start = max(start, maps.get(s[i], -1)+1)
            res = max(res, i - start + 1)
            maps[s[i]] = i
        return res
```


> 思路 3
******- 时间复杂度: O(N)******- 空间复杂度: O(N)******

slide window 全家桶，第159题和第340题几乎一摸一样，改几个数字就AC了，堪称模版

beats 70.56%

```python
class Solution:
    def lengthOfLongestSubstring(self, s):
        """
        :type s: str
        :rtype: int
        """
        lookup = collections.defaultdict(int)
        l, r, counter, res = 0, 0, 0, 0
        while r < len(s):
            lookup[s[r]] += 1
            if lookup[s[r]] == 1:
                counter += 1
            r += 1
            # counter < r - l 说明有重复字符出现，正常为counter == r - l
            while l < r and counter < r - l:
                lookup[s[l]] -= 1
                if lookup[s[l]] == 0:
                    counter -= 1
                l += 1
            res = max(res, r - l)
        return res
```
