前端算法題 | 這道題效率最高的算法,你可能不知道?

尋找最長的不含有重複字符的子串

可能看標題不會明白這個題到底什麼意思,來看看下面的例子:算法

  • abcabcbb ➡ abc ➡ 3
  • bbbb ➡ b ➡ 1
  • pwwkew ➡ wke ➡ 3

看了栗子是否是明白了呢?spa

其實需求很簡單,實現的方法也不少,不過在這裏我要來寫一種效率最高的算法,只須要一次循環就可解決:code

function findNoRepeatMaxLenStr (str) {
  let lastPositions = {}
  let start = 0
  let maxLen = 0

  for (let i=0; i<str.length; i++) {
        const s = str[i]
        if (lastPositions[s] !== 'undefined' && lastPositions[s] >= start) {
              start = lastPositions[s] + 1
        }
        if (i - start + 1 > maxLen) {
              maxLen = i - start + 1
        }
    lastPositions[s] = i
  }
  return maxLen
}

// test
console.log(findNoRepeatMaxLenStr('abcabcbb'))  // 3
複製代碼

那麼看完代碼,請本身先胡思亂想一下,能看得懂不?cdn

行了,看到這我就知道你沒看懂,那麼來解釋一下吧。blog

思路是這樣的,假以下面的圖形是一個字符串,每一個格子表明一個字符:索引

此時我們開始使用 for 循環掃描整個字符串,當掃描到 x(x 表明任意位置的任意的字符串)的時候,那麼我們應該怎麼作呢?ip

首先要記錄一個 start 起始位置,固然一開始就是 0 了,那麼 start 在循環中不單單只是表示字符串從 0 開始,還表示當前不含有最長重複子串的開始,那麼我們要作的事情就一件:保證從 start 到 x 之間沒有重複的字符串,再說的通俗點就是看檢查 start 到 x 之間有沒有重複的 x 。leetcode

那麼怎麼作到檢查這個動做呢?字符串

這個時候 lastPositions 就派上用場了。當循環到 x 的時候,記錄一下這個 x 最後一次出現的位置在哪裏。get

那麼記錄完畢以後,當進行檢查 start 到 x 之間 是否有重複的 x 的時候,我們就去問 lastPositions[x],此時會有2種狀況:

  • 第一種狀況是 x 歷來沒有出現過或者出如今了 start 以前;
  • 第二種狀況是 x 出如今 start 到 x 中間。

那麼對於第一種狀況,我們不用去管。而第二種狀況天然是不知足條件的狀況了,此時,我們就要更新 lastPositions[x],將這個 x 的位置更新爲 lastPositions[x] + 1。

總結下來就是:

lastPositions[x] 不存在或 < start 知足條件,無需操做 lastPositions[x] 存在而且 >= start 不知足條件,更新 lastPositions[x]++ 那麼在結合上面的代碼,邏輯就清晰了,惟一有些繞圈圈的地方就是第二個 if 中的 +1 操做,緣由就是字符串的索引是從 0 開始的,那麼假如第一個爲 x 知足條件,實際索引是0,那麼長度應該是 0 + 1 = 1。

最後,這道算法題的出處來自:

leetcode.com/problems/lo…

裏面有各類各樣的實現方法,能夠做爲參考。

以爲本文對你有幫助?請分享給更多人

相關文章
相關標籤/搜索