​LeetCode刷題實戰54:螺旋矩陣

2021-03-02 程序IT圈

算法的重要性,我就不多說了吧,想去大廠,就必須要經過基礎知識和業務邏輯面試+算法面試。所以,為了提高大家的算法能力,這個公眾號後續每天帶大家做一道算法題,題目就從LeetCode上面選 !

今天和大家聊的問題叫做 螺旋矩陣,我們先來看題面:

https://leetcode-cn.com/problems/spiral-matrix/

Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order.

題意給定一個包含 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]

解題https://www.cnblogs.com/techflow/p/12790451.html通過螺旋丸我們都知道螺旋形是什麼意思,所以所謂的螺旋矩陣,就是按照螺旋形的順序來遍歷一個數組,或者說矩陣。我們可以看下下圖:箭頭標註的順序就是螺旋的順序,這道題讓我們求的就是按照螺旋的順序遍歷之後的結果。背景這道題的題意非常簡單,我想大家肯定都能看明白,但是真的要上手去做會發現還是蠻困難的。主要的難點就是我們遍歷的順序一直在變化,並且變化的速度也是在變化的。雖然從某種程度上來說,這些變化都是有跡可循的,但是即便如此,把這些規律抽象出來寫成簡單易懂沒有bug的代碼也並不是一件容易的事情。如果我沒有記錯的話,當年我大二的時候學校裡的acm校賽有一題就是這個,一模一樣的原題。雖然非常簡單,每個人都知道怎麼做,但是最後的通過率並不高。這並不完全是出題人的惡意,其實這類問題在acm的比賽當中還是很常見的。經常會有一些題目很清晰明確,你只需要照著實現就可以了的題目。考察的就是選手的抽象和編碼能力,雖然題意不難,但是在比賽高壓的場景下想要快速寫出一個幾百行包含一系列複雜邏輯的程序並且沒有bug,還是非常困難的一件事。由於這類題目的關鍵就是讓我們模擬出來題目的意思,所以也被稱為模擬題。想要比較順手地寫出這道題,需要一個很常用的技巧或者說慣例,這也是這篇文章的關鍵。方向數組在許多問題當中我們經常會遇到這樣一個問題,比如我們需要遍歷一個迷宮,需要沿著現實世界當中上下左右或者是東南西北的方向進行移動。在移動的過程當中自然就涉及各種各樣的方向,於是我們需要用代碼來表示方向。比如我們畫一個小人,它所在的坐標是(x, y),它有東南西北四個方向可以選。我們假設他每次移動一個單位的距離,我們很容易就得出它往各個方向移動之後的新坐標。根據數學上向量的定義,我們可以寫出這四個方向的方向單位向量:[0, 1], [0, -1], [1, 0], [-1, 0]。我們把這些向量存放進一個常量數組當中,就得到了方向數組。當我們需要遍歷所有方向的時候,我們只需要遍歷這個數組即可。不僅如此,如果我們對方向的遍歷順序有要求,它也完全可以實現。比如在這題當中,我們可以發現,螺旋遍歷每一次改變順序其實都是向左轉了90度。原本朝東的旋轉之後變成了朝南,朝南的變成了朝西,朝西的成了朝北,而朝北的成了朝東。那麼我們只需要把方向按照東南西北的順序擺放,我們每次把方向數組的下標增加一位並對4取模,就得到了下一個方向。解答理解了方向數組之後剩下的就容易多了,我們觀察一下上面螺旋遍歷的過程,每一次改變方向遍歷的長度雖然不同,但是每一次改變的原因是一致的,就是這個方向上已經遍歷到頭了,所以我們需要變更方向。明白了這點其實就很容易了,我們只需要維護每個方向上的終點,每次到終點則進行變向。由於矩陣當中元素的數量是固定的,我們遍歷的次數也就知道了,所以只要把變更方向的事情處理好,這道題也就解決了。
class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        # 定義方向數組
        fx = [[0, 1], [1, 0], [0, -1], [-1, 0]]
        n = len(matrix)
        if n == 0:
            return []
        m = len(matrix[0])
        
        ret = []
        # 定義邊界數組
        # 邊界數組和旋轉的順序也是對應的
        # 第一次旋轉之後上邊界+1,所以第0位是上邊界
        # 第二次旋轉之後,右邊界-1
        # 以此類推
        condition = [0, m-1, n-1, 0]
        x, y, dt = 0, 0, 0
        for i in range(n * m):
            ret.append(matrix[x][y])
            x_, y_ = x + fx[dt][0], y + fx[dt][1]
            # 如果已經越過邊界了,則需要轉向
            if x_ < condition[0] or x_ > condition[2] or y_ < condition[3] or y_ > condition[1]:
                # 更新邊界
                if dt in (1, 2):
                    condition[dt] -= 1
                else:
                    condition[dt] += 1
                    
                # 轉向,並且重新移動
                dt = (dt + 1) % 4
                x_, y_ = x+fx[dt][0], y+fx[dt][1]
                # print(x_, y_)
            x, y = x_, y_
            
        return ret

我們觀察一下代碼,還有一個我們剛才沒有提到的細節。我們在移動的時候,並不是直接在原變量上進行變更,因為如果一旦移動超界或者觸發其他非法的情況,那麼我們就無法回滾了。所以我們會創建新的x和y的變量來表示移動之後的位置,即使移動到了非法位置,也不會影響之前的結果。這也是一個常用的技巧,在Python當中,我們在變量末尾加上下劃線表示這是一個影子(克隆)變量。總結我個人認為今天的題目出得不錯,初學者很有必要親自動手做一下。因為在做題的過程當中我們可以很具體地學到方向數組這個很有用的解題技巧,它在搜索問題當中廣泛使用,可以說是做算法題必須會的技巧之一。可能你會覺得我們通過邊界判斷是否需要轉向的邏輯看起來有些複雜,這並不是必須的。我們也可以使用一些其他方法來代替,比如我們可以開闢一個數組記錄已經遍歷過的位置來代替邊界的判定,和使用邊界判定的方法相比,這樣做消耗的空間要更大一些,並且通過邊界判定的方法更加考驗思維一些,因此我個人比較推薦。好了,今天的文章就到這裡,如果覺得有所收穫,請順手點個在看或者轉發吧,你們的支持是我最大的動力。

相關焦點

  • 一起刷 leetcode 之螺旋矩陣(頭條和美團真題)
    問題或建議,請公眾號留言;如果你覺得文章對你有幫助,歡迎關注與轉發題目描述給定一個包含 m*n 個元素的矩陣(m 行,n 列),請按順時針螺旋順序,返回矩陣中所有元素leetcode 第 54 題https://leetcode-cn.com/problems/spiral-matrix/示例示例 1
  • ​LeetCode刷題實戰85: 最大矩形
    所以,為了提高大家的算法能力,這個公眾號後續每天帶大家做一道算法題,題目就從LeetCode上面選 !今天和大家聊的問題叫做 最大矩形,我們先來看題面:https://leetcode-cn.com/problems/maximal-rectangle/Given a rows x cols binary matrix filled with 0's and 1's, find the largest rectangle containing
  • ​LeetCode刷題實戰139:單詞拆分
    所以,為了提高大家的算法能力,這個公眾號後續每天帶大家做一道算法題,題目就從LeetCode上面選 !今天和大家聊的問題叫做 單詞拆分,我們先來看題面:https://leetcode-cn.com/problems/word-break/Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be
  • 帶你狂刷算法Leetcode題!短時間內快速獲得實戰能力!
    但對於初學者來說,很容易沉迷在刷題的數量中,覺得如果能刷完這1000道題,自己一定能夠有所飛躍。但實際上,低效率的重複對你來說,根本就無法掌握到解題的精髓,一旦題目有所變動,就無法舉一反三。那究竟應該怎麼刷題才高效呢?
  • ​LeetCode刷題實戰79:單詞搜索
    所以,為了提高大家的算法能力,這個公眾號後續每天帶大家做一道算法題,題目就從LeetCode上面選 !今天和大家聊的問題叫做 單詞搜索,我們先來看題面:https://leetcode-cn.com/problems/word-search/Given a 2D board and a word, find if the word exists in the grid.
  • Go 刷 LeetCode 系列:螺旋矩陣
    歸納:   對於螺旋矩陣之類的題目有很多變形
  • ​LeetCode刷題實戰36: 有效的數獨
    所以,為了提高大家的算法能力,這個公眾號後續每天帶大家做一道算法題,題目就從LeetCode上面選 !今天和大家聊的問題叫做 有效的數獨,我們先來看題面:https://leetcode-cn.com/problems/valid-sudoku/Determine if a 9x9 Sudoku board is valid.
  • ​LeetCode刷題實戰198:打家劫舍
    所以,為了提高大家的算法能力,這個公眾號後續每天帶大家做一道算法題,題目就從LeetCode上面選 !今天和大家聊的問題叫做 打家劫舍,我們先來看題面:https://leetcode-cn.com/problems/house-robber/You are a professional robber planning to rob houses along a street.
  • ​LeetCode刷題實戰42:接雨水
    所以,為了提高大家的算法能力,這個公眾號後續每天帶大家做一道算法題,題目就從LeetCode上面選 !今天和大家聊的問題叫做 接雨水,我們先來看題面:https://leetcode-cn.com/problems/trapping-rain-water/Given n non-negative integers representing an elevation map where the width of each bar
  • ​LeetCode刷題實戰57:插入區間
    所以,為了提高大家的算法能力,這個公眾號後續每天帶大家做一道算法題,題目就從LeetCode上面選 !今天和大家聊的問題叫做 插入區間,我們先來看題面:https://leetcode-cn.com/problems/insert-interval/Given a set of non-overlapping intervals, insert a new interval into the intervals (merge
  • 【LeetCode溫故而知新】螺旋矩陣
    問題或建議,請公眾號留言;如果你覺得文章對你有幫助,歡迎關注分享題目 給定一個包含 m x n 個元素的矩陣(m 行, n 列),請按照順時針螺旋順序,返回矩陣中的所有元素。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]分析 這道題大概意思就是遍歷一個
  • ​LeetCode刷題實戰179:最大數
    所以,為了提高大家的算法能力,這個公眾號後續每天帶大家做一道算法題,題目就從LeetCode上面選 !今天和大家聊的問題叫做 最大數  ,我們先來看題面:https://leetcode-cn.com/problems/largest-number/Given a list of non-negative integers nums, arrange them such that they form the largest number.
  • ​LeetCode刷題實戰70:爬樓梯
    所以,為了提高大家的算法能力,這個公眾號後續每天帶大家做一道算法題,題目就從LeetCode上面選 !今天和大家聊的問題叫做 爬樓梯,我們先來看題面:https://leetcode-cn.com/problems/climbing-stairs/You are climbing a stair case.
  • ​LeetCode刷題實戰134:加油站
    所以,為了提高大家的算法能力,這個公眾號後續每天帶大家做一道算法題,題目就從LeetCode上面選 !https://leetcode-cn.com/problems/gas-station/There are N gas stations along a circular route, where the amount of gas at station i is gas[i].
  • 一個月帶你狂刷算法Leetcode題,衝刺最後秋招!
    (業務+邏輯+知識)這是一條由簡歷出發,由「知識」為切入點,不僅考察了「知識」的深度,而且還考察了「工具」、「業務」、「邏輯」深度的面試路徑,也是很多面試官通用的路徑不僅如此,除了《百面機器學習》,leetcode也是最經典的算法題庫,基本是面試官出題的」葵花寶典「,基本所有大大小小公司都會引用leetcode上的原題做為筆試。
  • 春節大禮包|刷題技巧+80道Leetcode
    為了跳槽,我前兩年的春節都是在刷題中度過的,目前為止刷了小四百道leetcode,也算是有一些經驗,今天就跟大家分享下學習方法和我總結的乾貨。後來發現了 Leetbook[1] 這個寶藏,才算是找到了適合自己的刷題方法。
  • ​LeetCode刷題實戰133:克隆圖
    所以,為了提高大家的算法能力,這個公眾號後續每天帶大家做一道算法題,題目就從LeetCode上面選 !https://leetcode-cn.com/problems/clone-graph/Given a reference of a node in a connected undirected graph.
  • ​LeetCode刷題實戰39:組合總和
    所以,為了提高大家的算法能力,這個公眾號後續每天帶大家做一道算法題,題目就從LeetCode上面選 !今天和大家聊的問題叫做 組合總和,我們先來看題面:https://leetcode-cn.com/problems/combination-sumGiven a set of candidate numbers (candidates) (without duplicates) and a target number (target
  • ​LeetCode刷題實戰72:編輯距離
    所以,為了提高大家的算法能力,這個公眾號後續每天帶大家做一道算法題,題目就從LeetCode上面選 !今天和大家聊的問題叫做 編輯距離,我們先來看題面:https://leetcode-cn.com/problems/edit-distanceGiven two words word1 and word2, find the minimum number of operations required to convert word1
  • leetcode刷題最強指南(版本1.0)
    為什麼會有這篇刷題指南很多剛開始刷題的同學都有一個困惑:面對leetcode上近兩千道題目,從何刷起