3. 无重复字符的最长子串|刷题打卡

130 阅读1分钟

一、题目描述

image.png

二、思路分析

滑动窗口的题,通过移动滑动窗口对字符串进行快照,通过对比快照的值获取最大的值。滑动窗口如何实现,双指针。通过移动双指针的左右指针来进行滑动。解题思路:

  1. 使用双指针来做一个滑动窗口;
  2. 右指针不断向右移动,遇到重复的时候移动左指针到重复的下一位;
  3. 比较每个窗口的长度,返回最大的长度 第一次写出来
var lengthOfLongestSubstring = function (s) {
  let l = 0;
  let res = 0;
  let map = new Map();
  for (let r = 0; r < s.length; r++) {
    if (map.has(s[r])) { // 细节 1
      l = map.get(s[r]) + 1;
    }

    map.set(s[r], r);
    res = Math.max(res, r - l); // 细节 2
  }

  return res;
};

存在什么问题吗?可以运行看一下,想想下面两个点:

  • 细节 1: 左指针移动细节,自己写完可以试一下("abba")。
  • 细节 2:如何计算长度问题。

解析:

  • 细节 1:发现左边的滑动窗口因为 map 存了之前所有的值,当abba 的时候会导致,窗口的左边界 l 错误。
  • 细节 2:是因为算值的时候需要加上本身的长度;
// ...
-     if (map.has(s[r])) { // 细节 1
+     if (map.has(s[r])  && map.get(s[r]) > l ) { // 细节 1
// ...
-     res = Math.max(res, r - l); // 细节 2
+     res = Math.max(res, r - l + 1);
// ...

还存在没有考虑到的情况吗?输入"abcabcbb"看一看?

  • 细节 1:因为没有考虑 l 往后移动完立马重复,r:4,l:2,r:5,map().get(c) = 2 出现问题了,加上等于 if (map.has(s[r]) && map.get(s[r]) >= l ) 即可; 所以完整的代码:
var lengthOfLongestSubstring = function (s) {
  let l = 0;
  let res = 0;
  let map = new Map();
  for (let r = 0; r < s.length; r++) {
    if (map.has(s[r]) && map.get(s[r]) >= l) {
      l = map.get(s[r]) + 1;
    }

    map.set(s[r], r);
    res = Math.max(res, r - l + 1);
  }

  return res;
};

复杂度分析:

  • 时间复杂度:O(N),遍历一次字符串
  • 空间复杂度:O(∣Σ∣), ∣Σ∣ 为字符集,因为在 Map 里面存储的唯一 key ,最多就是出现所有字符。

三、总结

本题的关键,就是在读完题之后能够分析想到滑动窗口,是一道典型的滑动窗口题目,滑动窗口实现方法双指针,后面多注意不同情况的细节就可以。