无重复字符的最长子串

224 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情

一、描述

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

示例 1:

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

示例 2:

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

示例 3:

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

提示:

  • 0 <= s.length <= 5 * 10^4
  • s 由英文字母、数字、符号和空格组成

leetcode

二、分析

子串一定连续!子序列不一定连续!

子串必须以i字符结尾时的最长,字符串的每个位置过一遍,就求出了答案 max = Math.max(max,xx)

因为不管哪个子串,一定以某个位置结尾,把所有位置求一遍,答案必在其中

那么怎么求每个位置的答案呢?

假设来到了i位置(字符a),它能往左推到的距离有多远?能往左推多远,取决于因素一和因素二哪个离我近

有两种可能性:

  • 上次a出现的位置(因素一)
  • i-1位置结尾往左推了多远(因素二)

上次a出现的位置比较近

image.png

i-1位置结尾往左推的距离比较近

image.png

优化:数组实现哈希表功能

三、实现

public static int lengthOfLongestSubstring(String s) {
    if (s == null || s.equals("")) {
        return 0;
    }
    char[] str = s.toCharArray();
    // map (a, ?) (b, ?)
    // a, 17
    // map[97] = 17
    int[] map = new int[256];
    for (int i = 0; i < 256; i++) {
        map[i] = -1;
    }
    // 收集答案
    int len = 0;
    int pre = -1; // i-1位置结尾的情况下,往左推,推不动的位置是谁
    int cur = 0;
    for (int i = 0; i != str.length; i++) {
        // i位置结尾的情况下,往左推,推不动的位置是谁
        // pre (i-1信息) -> pre(i 结尾信息)
        pre = Math.max(pre, map[str[i]]);
        cur = i - pre;
        len = Math.max(len, cur);
        map[str[i]] = i;
    }
    return len;
}