前端進階算法6:一看就懂的隊列及配套算法題

引言

隊列這種數據結構,據瓶子君瞭解,前端須要瞭解的隊列結構主要有:雙端隊列、滑動窗口,它們都是算法中是比較經常使用的數據結構。前端

所以,本節主要內容爲:git

  • 數據結構:隊列(Queue)
  • 雙端隊列(Deque)
  • 雙端隊列的應用:翻轉字符串中的單詞
  • 滑動窗口
  • 滑動窗口應用:無重複字符的最長公共子串
  • 最後來一道 leetcode 題目:滑動窗口最大值問題

下面進入正文吧👇github

1、數據結構:隊列

隊列和棧相似,不一樣的是隊列是先進先出 (FIFO) 原則的有序集合,它的結構相似以下:web

常見隊列的操做有:enqueue(e) 進隊、 dequeue() 出隊、 isEmpty() 是不是空隊、 front() 獲取隊頭元素、clear() 清空隊,以及 size() 獲取隊列長度。面試

代碼實現算法

function Queue({
  let items = []
  this.enqueue = function(e{
    items.push(e)
  }
  this.dequeue = function({
    return items.shift()
  }
  this.isEmpty = function({
    return items.length === 0
  }
  this.front = function({
    return items[0]
  }
  this.clear = function(
    items = [] 
  }
  this.size = function({
    return items.length
  }
}

查找:從對頭開始查找,從時間複雜度爲 O(n)編程

插入或刪除:進棧與出棧的時間複雜度爲 O(1)數組

2、雙端隊列(Deque)

1. 什麼是 Deque

Deque 在原有隊列的基礎上擴充了:隊頭、隊尾均可以進隊出隊,它的數據結構以下:瀏覽器

代碼實現:緩存

function Deque({
  let items = []
  this.addFirst = function(e{
    items.unshift(e)
  }
  this.removeFirst = function({
    return items.shift()
  }
  this.addLast = function(e{
    items.push(e)
  }
  this.removeLast = function({
    return items.pop()
  }
  this.isEmpty = function({
    return items.length === 0
  }
  this.front = function({
    return items[0]
  }
  this.clear = function(
    items = [] 
  }
  this.size = function({
    return items.length
  }
}

下面看一道經典的雙端隊列問題👇

2. 字節&leetcode151:翻轉字符串裏的單詞

給定一個字符串,逐個翻轉字符串中的每一個單詞。

示例 1:

輸入: "the sky is blue"
輸出: "blue is sky the"

示例 2:

輸入: "  hello world!  "
輸出: "world! hello"
解釋: 輸入字符串能夠在前面或者後面包含多餘的空格,可是反轉後的字符不能包括。

示例 3:

輸入: "a good   example"
輸出: "example good a"
解釋: 若是兩個單詞間有多餘的空格,將反轉後單詞間的空格減小到只含一個。

說明:

  • 無空格字符構成一個單詞。
  • 輸入字符串能夠在前面或者後面包含多餘的空格,可是反轉後的字符不能包括。
  • 若是兩個單詞間有多餘的空格,將反轉後單詞間的空格減小到只含一個。

解題思路:使用雙端隊列解題

  • 首先去除字符串左右空格
  • 逐個讀取字符串中的每一個單詞,依次放入雙端隊列的對頭
  • 再將隊列轉換成字符串輸出(已空格爲分隔符)

畫圖理解:

代碼實現:

var reverseWords = function(s{
    let left = 0
    let right = s.length - 1
    let queue = []
    let word = ''
    while (s.charAt(left) === ' ') left ++
    while (s.charAt(right) === ' ') right --
    while (left <= right) {
        let char = s.charAt(left)
        if (char === ' ' && word) {
            queue.unshift(word)
            word = ''
        } else if (char !== ' '){
            word += char
        }
        left++
    }
    queue.unshift(word)
    return queue.join(' ')
};

更多解法詳見 圖解字節&leetcode151:翻轉字符串裏的單詞

3、滑動窗口

1. 什麼是滑動窗口

這是隊列的另外一個重要應用

顧名思義,滑動窗口就是一個運行在一個大數組上的子列表,該數組是一個底層元素集合。

假設有數組 [a b c d e f g h ],一個大小爲 3 的 滑動窗口在其上滑動,則有:

[a b c]
  [b c d]
    [c d e]
      [d e f]
        [e f g]
          [f g h]

通常狀況下就是使用這個窗口在數組的 合法區間 內進行滑動,同時 動態地 記錄一些有用的數據,不少狀況下,可以極大地提升算法地效率。

下面看一道經典的滑動窗口問題👇

2. 字節&Leetcode3:無重複字符的最長子串

給定一個字符串,請你找出其中不含有重複字符的 最長子串 的長度。

示例 1:

輸入: "abcabcbb"
輸出: 3 
解釋: 由於無重複字符的最長子串是 "abc",因此其長度爲 3

示例 2:

輸入: "bbbbb"
輸出: 1
解釋: 由於無重複字符的最長子串是 "b",因此其長度爲 1

示例 3:

輸入: "pwwkew"
輸出: 3
解釋: 由於無重複字符的最長子串是 "wke",因此其長度爲 3
     請注意,你的答案必須是 子串 的長度,"pwke" 是一個子序列,不是子串。

解題思路: 使用一個數組來維護滑動窗口

遍歷字符串,判斷字符是否在滑動窗口數組裏

  • 不在則 push 進數組
  • 在則刪除滑動窗口數組裏相同字符及相同字符前的字符,而後將當前字符 push 進數組
  • 而後將 max 更新爲當前最長子串的長度

遍歷完,返回 max 便可

畫圖幫助理解一下:

代碼實現:

var lengthOfLongestSubstring = function(s{
    let arr = [], max = 0
    for(let i = 0; i < s.length; 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
};

時間複雜度:O(n2), 其中 arr.indexOf() 時間複雜度爲 O(n) ,arr.splice(0, index+1) 的時間複雜度也爲 O(n)

空間複雜度:O(n)

更多解法詳見 字節&Leetcode3:無重複字符的最長子串

最後,來嘗試一道leetcode題目吧!

4、leetcode239:滑動窗口最大值問題

給定一個數組 nums 和滑動窗口的大小 k,請找出全部滑動窗口裏的最大值。

示例:

輸入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
輸出: [3,3,5,5,6,7

解釋:

滑動窗口的位置                最大值

[1  3  -1] -3  5  3  6  7       3 

 1 [3  -1  -3] 5  3  6  7       3 

1  3 [-1  -3  5] 3  6  7       5 

 1  3  -1 [-3  5  3] 6  7       5 

 1  3  -1  -3 [5  3  6] 7       6 

 1  3  -1  -3  5 [3  6  7]      7

提示:

你能夠假設 k 老是有效的,在輸入數組不爲空的狀況下,1 ≤ k ≤ 輸入數組的大小。

能夠本身嘗試解答一下,歡迎將答案提交到 https://github.com/sisterAn/JavaScript-Algorithms/issues/33 ,瓶子君將明日解答😊

5、往期精彩

6、前端算法集訓營第一期免費加入啦

歡迎關注「前端瓶子君」,回覆「算法」自動加入,從0到1構建完整的數據結構與算法體系!

在這裏,瓶子君不只介紹算法,還將算法與前端各個領域進行結合,包括瀏覽器、HTTP、V八、React、Vue源碼等。

在這裏,你能夠天天學習一道大廠算法題(阿里、騰訊、百度、字節等等)或 leetcode,瓶子君都會在次日解答喲!

⬆️ 掃碼關注公衆號「前端瓶子君」,回覆「算法」便可自動加入 👍👍👍

「在看轉發」是最大的支持

本文分享自微信公衆號 - 前端瓶子君(pinzi_com)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索