先跳到第三题是由于第二题第一眼没读懂
无重复字符的最长子串:html
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。es6
示例1
输入: "abcabcbb"
输出: 3
解释: 由于无重复字符的最长子串是 "abc",因此其长度为 3。segmentfault示例2
输入: "bbbbb"
输出: 1
解释: 由于无重复字符的最长子串是 "b",因此其长度为 1。服务器示例3
输入: "pwwkew"
输出: 3
解释: 由于无重复字符的最长子串是 "wke",因此其长度为 3。函数请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
由于这道题以前在学校刷题的时候见过相似的,大概记得解法,就先放本身的思路测试
/** * @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 };
讲解优化
两个指针用来遍历字符串,begin指向当前字符串的头,end指向当前字符串的下一位spa
let begin = 0, end = 1
若是当前字符串不包含重复字符串,则判断是否更新结果(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为例,遍历的过程以下图
写完v1.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甚至比个人耗时还要多?去查了一下(查询结果),可能缘由为:一、服务器负载;二、测试用例增长。
奥~~这样啊
那对不起,个人就是最佳答案
/** *. @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; };