手摸手提桶跑路——LeetCode3.无重复的最长字串

135 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第26天,点击查看活动详情

题目描述

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

示例 1:

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

示例 2:

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

示例 3:

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

解法思路——暴力枚举

首先关注一下示例3,pwke 不算一个子串,而是一个序列。也就是说,子串是连续的,子序列是子元素组成的串。这就是这题的注意点了,千万不要写成了子序列然后 debug 半天。

那么既然是要找最长的子串,最简单的,对于字符串 s,用两层循环。我们可以用外层循环对字符串从每个下标 i 为起点,遍历从下标 i + 1s.length - 1 的字符串,一旦碰到重复的,就结束循环,统计当前的 不重复子串长度

题解

/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function(s) {
    const lens = s.length;
    let maxLens = 0;
    for(let i=0; i<lens; ++i) {
        let temp = s[i], cnt = 1;
        for(let j=i+1; j<lens; ++j) {
            if(temp.includes(s[j])) {
                break;
            }
            cnt++;
            temp+=s[j];
        }
        maxLens = Math.max(maxLens, cnt);
    }
    return maxLens;
};

微信截图_20220824022109.png

解题思路————滑动窗口+Set

暴力枚举需要对每个位置上的字符一直枚举到结尾,会有重复枚举的问题,极大的影响效率,那么有没有什么办法可以减少对字符串的遍历呢?

这里我们就需要使用 滑动窗口+Set 了。这里我使用两个变量 ij 来模拟滑动窗口的左右区间,同时为了方便查找区间的元素,所以使用 Set 来判断当前遍历到的字符是否存在于滑动窗口中。

  1. 首先滑动窗口不断向右移动。
  2. 判断当前遍历到的字符 w 是否存在于 Set 集合中。
  3. 如果不存在当前字符 w,那么就将当前元素添加到 Set 集合中(添加元素到滑窗中),并且将更新 maxLens 变量 maxLens = Math.max(maxLens. Set.size)
  4. 如果存在当前字符 w,则我们要将 Set 集合中 w 字符 及其之前 的所有字符都 删除,然后当前字符重新添加到 Set 集合中(这个步骤有点表述不清,拿字符串 pwwkerw 来说,我们到第一个 w 为止,滑窗的 size = 2,所有字符为 pw,那么遍历到第二个 w 的时候,我们为了让滑窗中的 子串 没有重复字符,那么 pww 这个字符串,我们需要删除前两个字符,才能保证 子串 是不含重复字符的)。
  5. 重复 2、3、4 步骤,最后输出 maxLens

题解

/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function(s) {
    const lens = s.length, wordSet = new Set();
    if(lens === 0) return 0;
    else if(lens === 1) return 1;
    let maxLens = 0;
    let i=0, j=0;
    while(i < lens) {
        if(!wordSet.has(s[i])) {
            wordSet.add(s[i]);
            maxLens = Math.max(wordSet.size, maxLens);
        } else {
            while(wordSet.has(s[i])) {
                wordSet.delete(s[j]);
                j++;
            }
            wordSet.add(s[i]);
        }
        i++;
    }
    return maxLens;
};