每日一题 -- LeetCode II 016

104 阅读3分钟

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

前言

每日一题,轻松解题

每日一题为刷题系列 每日刷一题LeetCode题,并且对题目进行分析,分享思路。

正文

:不含重复字符的最长子字符串

难度:中等

题目要求:

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

细节:这里说的是连续子字符串,而不是子序列,必须要是连续的不重复的。

举个例子

输入: a = abcddddddde
输出: 4
解释: 不含有重复字符的最长连续子字符串abcd。

:解题

方法一 :

理清思路:滑动窗口 + hashMap

滑动窗口算法思想是非常重要的一种思想,可以用来解决数组,字符串的子元素问题。它可以将嵌套循环的问题,转换为单层循环问题,降低时间复杂度,提高效率。

滑动窗口的思想非常简单,它将子数组(子字符串)理解成一个滑动的窗口,然后将这个窗口在数组上滑动,在窗口滑动的过程中,左边会出一个元素,右边会进一个元素,然后只需要计算当前窗口内的元素值即可。

可用滑动窗口思想解决的问题,一般有如下特点:

  • 窗口内元素是连续的。就是说,抽象出来的这个可滑动的窗口,在原数组或字符串上是连续的。
  • 窗口只能由左向右滑动,不能逆过来滑动。就是说,窗口的左右边界,只能从左到右增加,不能减少,即使局部也不可以。

算法思路

1、使用双指针中的左右指针技巧,初始化 left = right = 0,把索引闭区间 [left, right] 称为一个「窗口」。
2、先不断地增加 right 指针扩大窗口 [left, right],直到窗口符合要求。
3、停止增加 right,转而不断增加 left 指针缩小窗口 [left, right],直到窗口中的字符串不再符合要求。同时,每次增加 left,我们都要更新一轮结果。
4、重复第 2 和第 3 步,直到 right 到达尽头。

编辑代码:

var findAnagrams = function(s, p) {
    const m = s.length,
          n = p.length,
          letterArr = [],
          res = []; //收集起始索引的结果
    if(n > m){
        return res;
    }
    // 初始化26个英文字母的字符数,为0
    for(let i = 0;i <= 26;i++){
        letterArr.push(0);
    }
    // 收集p字符串的字符
    for(let j = 0;j < n;j++){
        letterArr[p[j].charCodeAt() - "a".charCodeAt()]--;
    }
    // 定义开始指针
    let left = 0;
    for(let right = 0;right < m;right++){
        const x = s[right].charCodeAt() - "a".charCodeAt();
        letterArr[x]++;
        while(letterArr[x] > 0){
            letterArr[s[left].charCodeAt() - "a".charCodeAt()]--;
            left++;
        }
        if(right - left + 1 === n){
            //此时left就是满足条件的起始索引
            res.push(left);
        }
    }
    return res;
};

总结

无论做什么分析最重要,其中我们分析了题目,分析了解题思路,其实在分析完解题思路后,代码其实就是很简单的事情了,养成习惯,无论做什么之前,都要进行分析,这样有助于你更快更好的完成这件事。