# 0003. Longest Substring Without Repeating Characters ###### tags: `Leetcode` `Medium` `Sliding Window` Link: https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/ ## 思路 ### 方法一 Sliding Window 如果我们依次递增地枚举子串的起始位置,那么子串的结束位置也是递增的!所以可以使用「滑动窗口」来解决这个问题了 用map记录当前字符最近出现过的位置,如果不在window里面,that's fine, 如果在的话,就要把left挪到最近出现过的位置+1 ### 方法二 动态规划 * 状态定义: 设动态规划列表 $dp$ ,$dp[j]$ 代表以字符 $s[j]$ 为结尾的 “最长不重复子字符串” 的长度。 * 转移方程: 固定右边界 $j$ ,设字符 $s[j]$ 左边距离最近的相同字符为 $s[i]$ ,即 $s[i] = s[j]$ 。 - 当 $i < 0$ ,即 $s[j]$ 左边无相同字符,则 $dp[j] = dp[j-1] + 1$ ; - 当 $dp[j - 1] < j - i$ ,说明字符 $s[i]$ 在子字符串 $dp[j−1]$ 区间之外 ,则 $dp[j] = dp[j - 1] + 1$ ; - 当 $dp[j - 1] \geq j - i$ ,说明字符 $s[i]$ 在子字符串 $dp[j-1]$ 区间之中 ,则 $dp[j]$ 的左边界由 $s[i]$ 决定,即 $dp[j] = j - i$ ; \begin{equation} dp[j] = \left\{ \begin{array}{rcl} dp[j-1]+1,& & {dp[j-1]<j-i}\\ j-i, & & {dp[j-1]\geq j-i}\\ \end{array} \right. \end{equation} ### 方法三 用map记录之前出现过的所有字符及最后出现的位置 后来做题的时候想到的方法 如题,遍历字符串,并用map记录之前出现过的所有字符及最后出现的位置 接着分两种情况 * 如果一个字符s[i]出现过,也就是map.contains = true那么就更新他的value值,并且length也要减掉s[i]-map.get(s[i])(上次出现过的位置),start(新的不重复字符串的起始点)也要改成i,但注意如果map.get(s[i])已经小于start了,例如s = "tmmzuxt",遇到第二个t时的状况,则不需要更新length * 如果没出现过,则length++,并跟maxLength比较看是否需要更新 ## Code ### 方法一 ```java= class Solution { public int lengthOfLongestSubstring(String s) { Map<Character, Integer> map = new HashMap<>(); int l=0, r=0, ans=0; while(r<s.length()){ char c = s.charAt(r); if(map.containsKey(c) && map.get(c)>=l){ ans=Math.max(ans, r-l); l=map.get(c)+1; } map.put(c,r); r++; } ans = Math.max(ans, r-l); return ans; } } ``` ### 方法三 ```java= class Solution { public int lengthOfLongestSubstring(String s) { Map<Character, Integer> dic = new HashMap<>(); int res = 0, tmp = 0; for(int j = 0; j < s.length(); j++) { int i = dic.getOrDefault(s.charAt(j), -1); // 获取索引 i dic.put(s.charAt(j), j); // 更新哈希表 tmp = tmp < j - i ? tmp + 1 : j - i; // dp[j - 1] -> dp[j] res = Math.max(res, tmp); // max(dp[j - 1], dp[j]) } return res; } } ``` ### 方法四 ```java= class Solution { public int lengthOfLongestSubstring(String s) { if(s == "") return 0; int maxLength = 0; int length = 0; int start = 0; HashMap<Character,Integer> hashMap = new HashMap<>(); for(int i = 0;i < s.length();i++){ char currChar = s.charAt(i); if(hashMap.containsKey(currChar)){ if(hashMap.get(currChar)<start){ hashMap.put(s.charAt(i),i); length++; } else { if (length > maxLength) { maxLength = length; } length -= hashMap.get(currChar) - start; start = hashMap.get(currChar) + 1; hashMap.put(s.charAt(i), i); } } else{ hashMap.put(s.charAt(i),i); length++; } if(length > maxLength){ maxLength = length; } } return maxLength; } } ```