LeetCode.3 无重复字符的最长子串(JS)

先跳到第三题是由于第二题第一眼没读懂

1、题目

无重复字符的最长子串:html

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

示例1

输入: "abcabcbb"
输出: 3
解释: 由于无重复字符的最长子串是 "abc",因此其长度为 3。segmentfault

示例2

输入: "bbbbb"
输出: 1
解释: 由于无重复字符的最长子串是 "b",因此其长度为 1。服务器

示例3

输入: "pwwkew"
输出: 3
解释: 由于无重复字符的最长子串是 "wke",因此其长度为 3。函数

请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

2、个人答案

由于这道题以前在学校刷题的时候见过相似的,大概记得解法,就先放本身的思路测试

v1.0

/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
  let resultLength = 0
  function hasEchoChar(str){
    return new Set(str).size !== str.length ? true : false
  }
  let begin = 0, end = 1;
  while(end <= s.length) {
    if (!hasEchoChar(s.slice(begin, end))) {
      end - begin > resultLength ? resultLength = end - begin : null;
      end++
    } else {
      begin++ 
    }
  }
  return resultLength
};

讲解优化

  1. 两个指针用来遍历字符串,begin指向当前字符串的头,end指向当前字符串的下一位spa

    let begin = 0, end = 1
  2. 若是当前字符串不包含重复字符串,则判断是否更新结果(resultLength)且end++,若是包含,begin++指针

    if (!hasEchoChar(s.slice(begin, end ))) {
      end - begin > resultLength ? resultLength = end - begin : null;
      end++
    } else {
      begin++ 
    }

           上文也说了以前碰到过相似的题,当时理解这部分用了很久,由于常写的循环都是只有一个指针变量的,像for(let i = 0; i < num; i++),若是按照惯用思路确定是循环套循环遍历全部子串,麻烦的丫批,上面这种写法妙就妙在一次循环中要么更新begin要么更新end,缩小了子串的筛选范围。code

           以示例3中的pwwkew为例,遍历的过程以下图
    便利过程

v2.0

写完v1.0代码,开心提交,经过是经过了,可是
v2.0产生的缘由
       我:???怎么肥四,一顿乱吹而后打败8%,神仙打架?仔细分析了一下,发现是判断是否包含重复字符的函数hasEchoChar的问题,在v1.0代码中我把子串转化成set结构而后对比先后length是否相等,由于set自动去重的特性,若是相等则没有重复字符。以此来实现判断是否包含重复字符。(这么写的缘由是上一题作完后去看了es6中Set和Map一章,上一题分析链接:我是连接)

function hasEchoChar(str){
    return new Set(str).size !== str.length ? true : false
}

       估计耗时就是耗在了转化成set结构了,这样写自己并没错,可是他的做用是判断一个任意字符串是否含有重复字符,咱们每次判断的是任意字符串吗?并非,那就不该该继续采用这种方法。
       聚光灯打到上文中展现遍历过程那张图,有重复字符的是pw->pww和wke->wkew,也就是说,只有每次end++时才有可能产生重复字符,也便是说咱们只须要判断上次遍历的字符串是否包含此次新添加的字符便可,思路理清,代码以下

/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function (s) {
  let resultLength = 0
  let begin = 0, end = 1
  while (end <= s.length) {
    let index = s.slice(begin, end - 1).indexOf(s[end - 1])
    if (index !== -1) {
      begin += (index + 1)
      end++
    } else {
      end - begin > resultLength ? resultLength = end - begin : null;
      end++
    }
  }
  return resultLength
};

       同时作出优化的部分还有找到相同字串的状况

if (index !== -1) {
  begin += (index + 1)
  end++
}

       在v1.0的代码中,每次找到相同字符就将begin指到下一个位置,若是还有呢,就再指向下一个位置,很明显begin能够一次指到位,即指到与当前子串末位相同字符位置的下一位,同时end++,开始下一轮的崭新循环。

       至此这道题我已经竭尽所能,执行用时从v1.0的956ms下降到v2.0的132ms,击败提交也从8.77%涨到71.88%。可是贪婪的我并不能知足于71.88%,因而去复制了一份耗时最低的答案本身提交,发现耗时140ms甚至比个人耗时还要多?去查了一下(查询结果),可能缘由为:一、服务器负载;二、测试用例增长。
       奥~~这样啊
       那对不起,个人就是最佳答案

3、优秀答案

/**
 *. @param {string} s
 *. @return {number}
 */
var lengthOfLongestSubstring = function(s) {
    let substr = '', maxLength = 0;
    for (var i = 0; i < s.length; i++) {
        let findIndex = substr.indexOf(s[i]);
        if (~findIndex) {
            substr = substr.substring(findIndex + 1);
        }
        substr += s[i];
        if (substr.length > maxLength) {
            maxLength = substr.length;
        }
    }
    return maxLength;
};
  1. 按位取反~
    以前从没见过~符号,搜了一下,是什么补码之类的,应该是大学计算机原理讲的东西(流下了悔恨的泪水),感兴趣的小伙伴能够看一下这个js中怎么理解按位取反?
  2. substring
    功能和slice相同相似,一样,感兴趣的小伙伴能够看一下MDN中substring的定义

4、路漫漫其修远兮

相关文章
相关标签/搜索