<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          ?LeetCode刷題實(shí)戰(zhàn)54:螺旋矩陣

          共 3414字,需瀏覽 7分鐘

           ·

          2020-10-03 07:30

          算法的重要性,我就不多說(shuō)了吧,想去大廠,就必須要經(jīng)過(guò)基礎(chǔ)知識(shí)和業(yè)務(wù)邏輯面試+算法面試。所以,為了提高大家的算法能力,這個(gè)公眾號(hào)后續(xù)每天帶大家做一道算法題,題目就從LeetCode上面選 !

          今天和大家聊的問(wèn)題叫做?螺旋矩陣,我們先來(lái)看題面:

          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.

          題意


          給定一個(gè)包含 m x n 個(gè)元素的矩陣(m 行, n 列),請(qǐng)按照順時(shí)針螺旋順序,返回矩陣中的所有元素。

          樣例

          示例?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

          通過(guò)螺旋丸我們都知道螺旋形是什么意思,所以所謂的螺旋矩陣,就是按照螺旋形的順序來(lái)遍歷一個(gè)數(shù)組,或者說(shuō)矩陣。我們可以看下下圖:
          箭頭標(biāo)注的順序就是螺旋的順序,這道題讓我們求的就是按照螺旋的順序遍歷之后的結(jié)果。

          背景

          這道題的題意非常簡(jiǎn)單,我想大家肯定都能看明白,但是真的要上手去做會(huì)發(fā)現(xiàn)還是蠻困難的。主要的難點(diǎn)就是我們遍歷的順序一直在變化,并且變化的速度也是在變化的。雖然從某種程度上來(lái)說(shuō),這些變化都是有跡可循的,但是即便如此,把這些規(guī)律抽象出來(lái)寫成簡(jiǎn)單易懂沒(méi)有bug的代碼也并不是一件容易的事情。
          如果我沒(méi)有記錯(cuò)的話,當(dāng)年我大二的時(shí)候?qū)W校里的acm校賽有一題就是這個(gè),一模一樣的原題。雖然非常簡(jiǎn)單,每個(gè)人都知道怎么做,但是最后的通過(guò)率并不高。
          這并不完全是出題人的惡意,其實(shí)這類問(wèn)題在acm的比賽當(dāng)中還是很常見(jiàn)的。經(jīng)常會(huì)有一些題目很清晰明確,你只需要照著實(shí)現(xiàn)就可以了的題目。考察的就是選手的抽象和編碼能力,雖然題意不難,但是在比賽高壓的場(chǎng)景下想要快速寫出一個(gè)幾百行包含一系列復(fù)雜邏輯的程序并且沒(méi)有bug,還是非常困難的一件事。由于這類題目的關(guān)鍵就是讓我們模擬出來(lái)題目的意思,所以也被稱為模擬題。
          想要比較順手地寫出這道題,需要一個(gè)很常用的技巧或者說(shuō)慣例,這也是這篇文章的關(guān)鍵。

          方向數(shù)組

          在許多問(wèn)題當(dāng)中我們經(jīng)常會(huì)遇到這樣一個(gè)問(wèn)題,比如我們需要遍歷一個(gè)迷宮,需要沿著現(xiàn)實(shí)世界當(dāng)中上下左右或者是東南西北的方向進(jìn)行移動(dòng)。在移動(dòng)的過(guò)程當(dāng)中自然就涉及各種各樣的方向,于是我們需要用代碼來(lái)表示方向。
          比如我們畫一個(gè)小人,它所在的坐標(biāo)是(x, y),它有東南西北四個(gè)方向可以選。我們假設(shè)他每次移動(dòng)一個(gè)單位的距離,我們很容易就得出它往各個(gè)方向移動(dòng)之后的新坐標(biāo)。
          根據(jù)數(shù)學(xué)上向量的定義,我們可以寫出這四個(gè)方向的方向單位向量:[0, 1], [0, -1], [1, 0], [-1, 0]。
          我們把這些向量存放進(jìn)一個(gè)常量數(shù)組當(dāng)中,就得到了方向數(shù)組。當(dāng)我們需要遍歷所有方向的時(shí)候,我們只需要遍歷這個(gè)數(shù)組即可。
          不僅如此,如果我們對(duì)方向的遍歷順序有要求,它也完全可以實(shí)現(xiàn)。比如在這題當(dāng)中,我們可以發(fā)現(xiàn),螺旋遍歷每一次改變順序其實(shí)都是向左轉(zhuǎn)了90度。
          原本朝東的旋轉(zhuǎn)之后變成了朝南,朝南的變成了朝西,朝西的成了朝北,而朝北的成了朝東。那么我們只需要把方向按照東南西北的順序擺放,我們每次把方向數(shù)組的下標(biāo)增加一位并對(duì)4取模,就得到了下一個(gè)方向。
          這個(gè)技巧并不難理解,但是可以大大簡(jiǎn)化我們的代碼。

          解答

          理解了方向數(shù)組之后剩下的就容易多了,我們觀察一下上面螺旋遍歷的過(guò)程,每一次改變方向遍歷的長(zhǎng)度雖然不同,但是每一次改變的原因是一致的,就是這個(gè)方向上已經(jīng)遍歷到頭了,所以我們需要變更方向。明白了這點(diǎn)其實(shí)就很容易了,我們只需要維護(hù)每個(gè)方向上的終點(diǎn),每次到終點(diǎn)則進(jìn)行變向。由于矩陣當(dāng)中元素的數(shù)量是固定的,我們遍歷的次數(shù)也就知道了,所以只要把變更方向的事情處理好,這道題也就解決了。
          我們來(lái)看下代碼:
          class?Solution:
          ????def?spiralOrder(self,?matrix:?List[List[int]])?->?List[int]:
          ????????#?定義方向數(shù)組
          ????????fx?=?[[0,?1],?[1,?0],?[0,?-1],?[-1,?0]]
          ????????n?=?len(matrix)
          ????????if?n?==?0:
          ????????????return?[]
          ????????m?=?len(matrix[0])
          ????????
          ????????ret?=?[]
          ????????#?定義邊界數(shù)組
          ????????#?邊界數(shù)組和旋轉(zhuǎn)的順序也是對(duì)應(yīng)的
          ????????#?第一次旋轉(zhuǎn)之后上邊界+1,所以第0位是上邊界
          ????????#?第二次旋轉(zhuǎn)之后,右邊界-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]
          ????????????#?如果已經(jīng)越過(guò)邊界了,則需要轉(zhuǎn)向
          ????????????if?x_?0]?or?x_?>?condition[2]?or?y_?3]?or?y_?>?condition[1]:
          ????????????????#?更新邊界
          ????????????????if?dt?in?(1,?2):
          ????????????????????condition[dt]?-=?1
          ????????????????else:
          ????????????????????condition[dt]?+=?1
          ????????????????????
          ????????????????#?轉(zhuǎn)向,并且重新移動(dòng)
          ????????????????dt?=?(dt?+?1)?%?4
          ????????????????x_,?y_?=?x+fx[dt][0],?y+fx[dt][1]
          ????????????????#?print(x_,?y_)
          ????????????x,?y?=?x_,?y_
          ????????????
          ????????return?ret
          我們觀察一下代碼,還有一個(gè)我們剛才沒(méi)有提到的細(xì)節(jié)。我們?cè)谝苿?dòng)的時(shí)候,并不是直接在原變量上進(jìn)行變更,因?yàn)槿绻坏┮苿?dòng)超界或者觸發(fā)其他非法的情況,那么我們就無(wú)法回滾了。所以我們會(huì)創(chuàng)建新的x和y的變量來(lái)表示移動(dòng)之后的位置,即使移動(dòng)到了非法位置,也不會(huì)影響之前的結(jié)果。這也是一個(gè)常用的技巧,在Python當(dāng)中,我們?cè)谧兞磕┪布由舷聞澗€表示這是一個(gè)影子(克?。┳兞俊?/section>

          總結(jié)

          我個(gè)人認(rèn)為今天的題目出得不錯(cuò),初學(xué)者很有必要親自動(dòng)手做一下。因?yàn)樵谧鲱}的過(guò)程當(dāng)中我們可以很具體地學(xué)到方向數(shù)組這個(gè)很有用的解題技巧,它在搜索問(wèn)題當(dāng)中廣泛使用,可以說(shuō)是做算法題必須會(huì)的技巧之一。
          可能你會(huì)覺(jué)得我們通過(guò)邊界判斷是否需要轉(zhuǎn)向的邏輯看起來(lái)有些復(fù)雜,這并不是必須的。我們也可以使用一些其他方法來(lái)代替,比如我們可以開(kāi)辟一個(gè)數(shù)組記錄已經(jīng)遍歷過(guò)的位置來(lái)代替邊界的判定,和使用邊界判定的方法相比,這樣做消耗的空間要更大一些,并且通過(guò)邊界判定的方法更加考驗(yàn)思維一些,因此我個(gè)人比較推薦。
          好了,今天的文章就到這里,如果覺(jué)得有所收獲,請(qǐng)順手點(diǎn)個(gè)在看或者轉(zhuǎn)發(fā)吧,你們的支持是我最大的動(dòng)力。


          上期推文:


          LeetCode1-50題匯總,速度收藏!
          LeetCode刷題實(shí)戰(zhàn)51:N 皇后
          LeetCode刷題實(shí)戰(zhàn)52:N皇后 II
          LeetCode刷題實(shí)戰(zhàn)53:最大子序和


          瀏覽 42
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产精品内射视频免费 | 毛片色毛片18毛片 | 操操干干 | 亚洲一区色 | 韩国在线一区二区三区 |