JS版數據結構第四篇(矩陣)

本篇博客參考銀國徽老師的《Javascript版數據結構與算法》

背景

其實從嚴格意義上來說矩陣不能算一種典型的數據結構javascript

而之因此把矩陣放到這個系列裏面是由於矩陣在面試和筆試中是很是高頻出現的java

今天咱們將會用js實現兩道LeetCode上兩道比較經典的矩陣相關的算法題面試

矩陣的定義對於大學學習過《線性代數》這門課程的同窗們來說應該都不會很陌生,若是有同窗不瞭解能夠自行查下百度百科。算法

很少廢話,咱們直接看題。數組

螺旋矩陣

LeetCode第54題 原題地址bash

題目難度: 中等數據結構

題目描述

給定一個包含 m x n 個元素的矩陣(m 行, n 列),請按照順時針螺旋順序,返回矩陣中的全部元素。

示例1:函數

輸入:
[
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
]
輸出: [1,2,3,6,9,8,7,4,5]複製代碼

示例2:學習

輸入:
[
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9,10,11,12]
]
輸出: [1,2,3,4,8,12,11,10,9,5,6,7]複製代碼

題目理解

題目要求的是咱們按照順時針的順序從外向內遍歷每個元素,並將他們按順序返回出來。ui


根據這張圖咱們應該很清除的理解題目的要求了,題目要求的元素的返回順序就是圖中的1到16

思路分析

咱們能夠注意到:

不管是幾×幾的矩陣,都是須要咱們先將外圈遍歷完成後才進入到它相鄰內圈元素的遍歷

如上圖中咱們將1-12看做第一圈,將13-16看做第二圈,第一圈所有遍歷完成後纔會遍歷第二圈

若是有階數更高的矩陣(更多圈數),還會有第三圈,第四圈的遍歷

因此咱們能夠把每一圈的遍歷視爲一個步驟,不斷地重複這個步驟就會獲得咱們須要的結果

相信有一些同窗已經猜出咱們要用遞歸解決這道題目了

接下來咱們看一下代碼具體是怎樣實現的

代碼實現

arr => {
    // map函數用來完成當前矩陣最外一圈的遍歷
    // @param1{Array}二維數組 arr 表示當前矩陣
    // @param2{Array}一維數組 result 用來保存遍歷結果 
    let map = (arr, result) => {
        // 矩陣的高度即行數
        let n = arr.length
        // 遍歷矩陣的每一行
        for(let i = 0; i < n; i++){
            // 若第一行 按順序插入
            if(i === 0){
                result = result.concat(arr[i])
            } else if (i === n-1){
                // 若最後一行 倒序插入
                result = result.concat(arr[i].reverse())
            } else {
                // 若中間行 插入該行最後一個元素 並將該元素從矩陣中刪除
                result.push(arr[i].pop())
            }
        }
        // 將已經遍歷的第一行和最後一行從矩陣中刪除
        arr.pop()
        arr.shift()
        // 遍歷插入最左側一列 此時刪除首位兩行後矩陣高度已變爲n-2
        for(let j = n - 3; j >= 0; j--){
            // 避免arr[j]長度爲空時插入undefined
            if(arr[j].length){
                result.push(arr[j].shift())
            }
        }
        // 截止條件 矩陣有元素就繼續遞歸
        if(arr.length){
            // 把已將遍歷元素刪除的矩陣進行遞歸
            return map(arr, result)
        }else{
            return result
        }
    }
    // 將初始矩陣傳入, 保存結果的數組初始爲空
    return map(arr, [])
}複製代碼

思考

可能有些同窗不太清除咱們是怎樣想到經過遞歸解決這樣的問題。

這裏根據我的的一些經驗 我總結了一下知足遞歸的三個通用條件:

  • 能夠將一個操做拆解爲處理過程相同的小步驟
  • 每次步驟的輸入數據格式都相同
  • 運行次數未知

在這個題目中

  • 首先咱們將順時針螺旋遍歷拆解爲每一圈的遍歷
  • 咱們最開始接收一個二維數組(矩陣),每次遍歷完成一圈後傳入刪除最外圈元素的新矩陣,它一樣是一個二維數組
  • 遞歸直到矩陣爲空(傳入的矩陣寬高並不肯定)

符合了遞歸的三個條件。

你們從此碰到相似的題目就能夠參照這三點來判斷是否可使用遞歸。

旋轉圖像

LeetCode第48題 原題地址

題目難度:中等

題目描述

給定一個 n × n 的二維矩陣表示一個圖像。 將圖像順時針旋轉 90 度。 
說明: 你必須在原地旋轉圖像,這意味着你須要直接修改輸入的二維矩陣。
請不要使用另外一個矩陣來旋轉圖像。

示例1:

給定 matrix =
 [
     [1,2,3], 
     [4,5,6], 
     [7,8,9] 
], 
 原地旋轉輸入矩陣,使其變爲: 
[
    [7,4,1], 
    [8,5,2], 
    [9,6,3] 
]

示例2:

給定 matrix = 
[
    [ 5, 1, 9,11],
    [ 2, 4, 8,10],
    [13, 3, 6, 7],
    [15,14,12,16]
]
 原地旋轉輸入矩陣,使其變爲: 
[
    [15,13, 2, 5],
    [14, 3, 4, 1],
    [12, 6, 8, 9],
    [16, 7,10,11]
]

題目理解

題目很好理解,直接將矩陣順時針旋轉,有點相似於咱們平時使用的將圖片順時針旋轉90度的功能

而這個題目之因此叫作'旋轉圖像'也正是由於這道題目的實現方法就是圖片旋轉功能的原理。

思路分析

表面上看這道題很簡單,咱們只須要創建一個新的矩陣(二維數組),而後遍歷原矩陣matrix的每一

列,按照從下到上的順序添加至新矩陣的每一行中便可。

可是這道題的難度就在於題目中要求咱們「原地旋轉圖像」,這意味着咱們不能夠新建一個二維數

組(矩陣),而後向裏面添加數據,咱們只能處理原矩陣,那處理原矩陣的話咱們除了將數字交換位置

之外並無其餘的方法了。

那具體怎樣交換呢?

以示例1爲例,首先咱們以中間行爲軸,將矩陣進行軸對稱


而後咱們再以對角線753做爲軸進行軸對稱


此時就獲得了咱們想要的結果,接下來咱們用代碼實現它

代碼實現

arr => {
    // 獲取矩陣階數
    let n = arr.length
    let temp
    // 垂直翻轉 考慮n的奇偶
    for(let i = 0; i < Math.floor(n / 2); i++){
        for(let j = 0; j< n; j++){
            temp = arr[i][j]
            arr[i][j] = arr[n -1 -i][j]
            arr[n -1 -i][j] = temp
        }
    }
    // 沿對角線反轉
    for(let p = 0;p < n - 1; p++){
        for(let q = p + 1; q < n; q++){
            temp = arr[p][q]
            arr[p][q] = arr[q][p]
            arr[q][p] = temp
        }
    }
    return arr
}複製代碼

總結

LeetCode上面也有不少有關矩陣的題目,你們均可以去嘗試着作一下,若是對個人方法有疑問也歡迎你們來評論區探討,多交流纔會有所進步,但願你早日成爲大牛。

相關文章
相關標籤/搜索