js 算法: 获取不含重复字符的最长字符串

901 阅读2分钟

这是我参与11月更文挑战的第27天,活动详情查看:2021最后一次更文挑战

背景

学习前端三个月了,准备刷刷面试题,总结总结,一天几道面试题,向大厂进军。

问题

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

示例1

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

示例2

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

示例3

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

解析

解法一: 使用数组来维护滑动窗口

先讲一下什么是滑动窗口: 窗口在我们我们代码中其实就是队列,那滑动代表的其实就是,这个删除队列左或者右两边的元素,这样看起来就是窗口左移或者右移。

再来看看我们这道题:

由于我们要取不含重复字符的最长字符串,所以我们要想到字符串中可能有很多不含重复字符的子字符串,我们要对比这些子串的长度。

  1. 这里我们先定义一个max=0,这里来记录当前最大子串的长度。

  2. 我们遍历字符串,判断当前字符是否在滑动窗口数组里

  • 不在则 push 进数组
  • 在则删除滑动窗口数组里相同字符及相同字符前的字符,然后将当前字符 push 进数组
  • 根据当前窗口的长度和记录的max 取最大值
  • 然后将 max 更新为当前最长子串的长度

遍历完,返回 max 即可。

我们用一张图来看一下:

image.png

代码实现:

    /**
     * @param {string} s
     * @return {number}
     */
    var lengthOfLongestSubstring = function(s) {
        //滑动窗口,也叫队列
         let arr = [];
         let max = 0;
         let len=s.length;
        for(let i = 0; i <len; i++) {
            let index = arr.indexOf(s[i])
            if(index !== -1) {
                //移动窗口,删除左边的元素
                arr.splice(0, index+1);
            }
            //存放当前字符
            arr.push(s.charAt(i))
            // 更新最大字符长度
            max = Math.max(arr.length, max) 
        }
        return max
    };

验证结果:

image.png

那我们扩展下题目

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

这里我们需要找出最长的字符串,而不是最长字符串的长度。

  1. 我们需要了解知道最长字符串,我们上面题目已经可以获取到最长字符串的长度。
  2. 我们只需要记住最长字符串开始的角标即可。
  3. 默认我们设置为0,
  4. 当窗口滑动的时候,我们根据当前的max是否比原来的字符串长度大,来判断是否需要替换开始index。
  5. 清空滑动窗口,比较max

我们来看代码:

    /**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function(s) {
    //滑动窗口,也叫队列
     let arr = [];
     let max = 0;
     let len=s.length;
     //记录最大字符串
     let start=0;
    for(let i = 0; i <len; i++) {
        let index = arr.indexOf(s[i])
         //字符串中有重复的
        if(index !== -1) {
              //判断当前的子串是否比上次获取的子串长度更大
             if(arr.length>max){
                //获取当前不重复子串的长度
                max=arr.length;
                //计算当前不重复子串的开始索引
                start=i-max;
            }
            //移动窗口,删除左边的元素
            arr.splice(0, index+1);
        }
        //存放当前字符
        arr.push(s.charAt(i))
    }
    //清空最后一次的窗口
     if(arr.length>max){
         max=arr.length;
         start=s.length-max;
     }
    return s.substr(start,max)
};

验证结果:

image.png

结语

一步一步慢慢来,踏踏实实把活干!