Leetcode-3. 无重复字符的最长子串

192 阅读2分钟

题目

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 2:

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:

输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

示例 4:

输入: s = ""
输出: 0

来源:力扣(LeetCode)
链接:leetcode-cn.com/problems/lo…
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路

  • 处理字符串重复问题

散列表,一般是字符为key,下标为value

  • 处理子串问题

滑动窗口

  • 本题思路
  1. 如果参数长度为0,则直接返回0

  2. 从第一个到最后一个字符遍历字符串,拿到当前字符串后去散列表中判断是否重复:如果没有重复,就向右扩大滑动窗口大小,并将当前下标存入散列表中;如果当前字符重复了,则先判断当前窗口是否比最大还大,如果是更新最大,然后从开始位置向右缩小窗口。至于缩小到哪里?应该是保证上一次该字符出现的位置,但是有可能随着窗口的缩小,上一次出现的位置比窗口开始位置还要小,因此,窗口缩小的位置应该是该字符上一次出现的位置和当前窗口起始位置取最大值。循环结束后可能最长的子串在最后,因此还需要再次判断当前窗口和最大值的大小。

算法

public int lengthOfLongestSubstring(String s) {
    if (s.length() == 0) {
        return 0;
    }

    // 处理重复使用散列表
    Map<Character, Integer> hashTable = new HashMap<>();
    int maxLength = 0;
    int currentLength = 0;
    int startIndex = 0;

    for (int i = 0; i < s.length(); i++) {
        if (!hashTable.containsKey(s.charAt(i))) {
            // 如果没有重复则扩大窗口大小
            currentLength++;
            // 并记录下标位置
            hashTable.put(s.charAt(i), i);
        } else {
            // 否则缩小窗口,缩小的位置取决于重复字符的位置
            // 缩小前需要将当前的长度记录下来
            if (currentLength > maxLength) {
                maxLength = currentLength;
            }
            // 缩小的位置是窗口当前起始位置与重复字符串位置取大的
            startIndex = hashTable.get(s.charAt(i)) > startIndex ? hashTable.get(s.charAt(i)) : startIndex;
            currentLength = i - startIndex;
            hashTable.put(s.charAt(i), i);
        }
    }

    if (currentLength > maxLength) {
        maxLength = currentLength;
    }
    return maxLength;
}