3. Longest Substring Without Repeating Characters

题目

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

Example 1:

  1. Input: "abcabcbb"
  2. Output: 3
  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.

题目大意

在一个字符串重寻找没有重复字母的最长子串。

解题思路

这一题和第 438 题,第 3 题,第 76 题,第 567 题类似,用的思想都是”滑动窗口”。

滑动窗口的右边界不断的右移,只要没有重复的字符,就持续向右扩大窗口边界。一旦出现了重复字符,就需要缩小左边界,直到重复的字符移出了左边界,然后继续移动滑动窗口的右边界。以此类推,每次移动需要计算当前长度,并判断是否需要更新最大长度,最终最大的值就是题目中的所求。

代码解析

简单解法

class Solution {

    public int lengthOfLongestSubstring(String s) {
        String str = "";
        int max = 0;
        for (int i = 0; i < s.length(); i++) {
            String c = Character.toString(s.charAt(i));
            if (str.contains(c)) {
                int index = str.indexOf(c);
                str = str.substring(index + 1);
                str += c;
            } else {
                str += c;
            }
            if (str.length() > max) {
                max = str.length();
            }
        }
        return max;
    }
}

优化解法

class Solution {

    public int lengthOfLongestSubstring(String s) {
        Map<Character, Integer> map = new HashMap();
        int max = 0;
        //left 滑动窗口左边界, right 正在滑动的索引(右边界)
        for (int left = 0, right = 0; right < s.length(); right++) {
            char c = s.charAt(right);
            if (map.containsKey(c)) {
                // map.get(c)+1 可能比 i 还小,通过 max 函数来锁住左边界
                //在"tmmzuxt"这个字符串中, 遍历到“tmm”时 左边界更新为“tm”后面“m”的位置
                //遍历到”tmmzuxt“时,map.get(c)会取到第一个t的位置,但是他已经不在left里面
                //因此这时窗口应该为“mzuxt”,左边界还是“m”的位置
                left = Math.max(left, map.get(c) + 1);
            }
            //会更新重复值的索引位置,下次遇到重复值时,左窗口将移动
            //遍历到”tmmzuxt“后下一个如果还是t那么窗口将从“tm|mzuxt|t”滑动到“tmmzuxt|t|”的位置
            map.put(c, right);
            max = Math.max(max, right - left + 1);
        }
        return max;
    }
}