On a 2 dimensional grid with R
rows and C
columns, we start at (r0, c0)
facing east.html
Here, the north-west corner of the grid is at the first row and column, and the south-east corner of the grid is at the last row and column.git
Now, we walk in a clockwise spiral shape to visit every position in this grid. github
Whenever we would move outside the boundary of the grid, we continue our walk outside the grid (but may return to the grid boundary later.) 數組
Eventually, we reach all R * C
spaces of the grid.ide
Return a list of coordinates representing the positions of the grid in the order they were visited.函數
Example 1:this
Input: R = 1, C = 4, r0 = 0, c0 = 0 Output: [[0,0],[0,1],[0,2],[0,3]]
Example 2:spa
Input: R = 5, C = 6, r0 = 1, c0 = 4 Output: [[1,4],[1,5],[2,5],[2,4],[2,3],[1,3],[0,3],[0,4],[0,5],[3,5],[3,4],[3,3],[3,2],[2,2],[1,2],[0,2],[4,5],[4,4],[4,3],[4,2],[4,1],[3,1],[2,1],[1,1],[0,1],[4,0],[3,0],[2,0],[1,0],[0,0]]
Note:3d
1 <= R <= 100
1 <= C <= 100
0 <= r0 < R
0 <= c0 < C
這道題給了咱們一個二維矩陣,還給了其中一個位置,讓從這個位置開始搓一個螺旋丸,哦不,是螺旋打印矩陣。具體怎麼螺旋打印呢,題目中給了例子,又給了示例圖,真的是很貼心呢。能夠看出來,首先是打印給定的位置,而後向右走一位,打印出來,再向下方走一位打印,再向左邊走兩位打印,再向上方走三位打印,以此類推,螺旋打印。那仔細觀察,能夠發現,剛開始只是走一步,後來步子愈來愈大,若只看每一個方向走的距離,能夠獲得以下數組 1,1,2,2,3,3... 步長有了,下面就是方向了,因爲肯定了起始是向右走,那麼方向就是 右->下->左->上 這樣的循環。方向和步長都分析清楚了,如今就能夠嘗試進行遍歷了。因爲最終是會遍歷完全部的位置的,那麼最後結果 res 裏面的位置個數必定是等於 RxC 的,因此循環的條件就是當結果 res 中的位置數小於 R*C。咱們還須要一個變量 step 表示當前的步長,初始化爲1。在循環中,首先要想右走 step 步,一步一步走,走到一個新的位置上,要進行判斷,若當前位置沒有越界,才能加入結果 res 中,因爲每次都要判斷,因此把這部分抽取出來,放到一個子函數中。因爲是向右走,每走一步以後,c0 都要自增1。右邊走完了以後,再向下方走 step 步,同理,每走一步以後,要將 r0 自增1。再向左邊走以前,要將步數增1,否則沒法造成正確的螺旋,同理,再完成向上方走 step 步以後,step 要再增1,參見代碼以下:code
解法一:
class Solution { public: vector<vector<int>> spiralMatrixIII(int R, int C, int r0, int c0) { vector<vector<int>> res; int step = 1; while (res.size() < R * C) { for (int i = 0; i < step; ++i) add(R, C, r0, c0++, res); for (int i = 0; i < step; ++i) add(R, C, r0++, c0, res); ++step; for (int i = 0; i < step; ++i) add(R, C, r0, c0--, res); for (int i = 0; i < step; ++i) add(R, C, r0--, c0, res); ++step; } return res; } void add(int R, int C, int x, int y, vector<vector<int>>& res) { if (x >= 0 && x < R && y >= 0 && y < C) res.push_back({x, y}); } };
上面的方法 for 循環太多,看的很木亂,能夠用兩個數組 dirX 和 dirY 來控制下一個方向,就像迷宮遍歷中的那樣,這樣只須要一個變量 cur,來分別到 dirX 和 dirY 中取值,初始化爲0,表示向右的方向。從螺旋遍歷的機制能夠看出,每當向右或者向左前進時,步長就要加1,那麼咱們只要判斷當 cur 爲0或者2的時候,step 就自增1。因爲 cur 初始化爲0,因此剛開始 step 就會增1,那麼就能夠將 step 初始化爲0,同時還須要把起始位置提早加入結果 res 中。此時在 while 循環中只須要一個 for 循環便可,朝當前的 cur 方向前進 step 步,r0 加上 dirX[cur],c0 加上 dirY[cur],若沒有越界,則加入結果 res 中便可。以後記得 cur 要自增1,爲了防止越界,對4取餘,就像循環數組同樣的操做,參見代碼以下:
解法二:
class Solution { public: vector<vector<int>> spiralMatrixIII(int R, int C, int r0, int c0) { vector<vector<int>> res{{r0, c0}}; vector<int> dirX{0, 1, 0, -1}, dirY{1, 0, -1, 0}; int step = 0, cur = 0; while (res.size() < R * C) { if (cur == 0 || cur == 2) ++step; for (int i = 0; i < step; ++i) { r0 += dirX[cur]; c0 += dirY[cur]; if (r0 >= 0 && r0 < R && c0 >= 0 && c0 < C) res.push_back({r0, c0}); } cur = (cur + 1) % 4; } return res; } };
咱們也能夠不使用方向數組,若仔細觀察 右->下->左->上 四個方向對應的值 (0, 1) -> (1, 0) -> (0, -1) -> (-1, 0), 實際上,下一個位置的x值是當前的y值,下一個位置的y值是當前的-x值,由於兩個方向是相鄰的兩個方向是垂直的,由向量的叉乘獲得 (x, y, 0) × (0, 0, 1) = (y, -x, 0)。因此能夠經過當前的x和y值,來計算出下一個位置的值。同理,根據以前的說的步長數組 1,1,2,2,3,3...,能夠推出通項公式爲 n/2 + 1,這樣連步長變量 step 都省了,不過須要統計當前已經遍歷的位置的個數,實在想偷懶,也能夠用 res.size() 來代替,參見代碼以下:
解法三:
class Solution { public: vector<vector<int>> spiralMatrixIII(int R, int C, int r0, int c0) { vector<vector<int>> res{{r0, c0}}; int x = 0, y = 1, t = 0; for (int k = 0; res.size() < R * C; ++k) { for (int i = 0; i < k / 2 + 1; ++i) { r0 += x; c0 += y; if (r0 >= 0 && r0 < R && c0 >= 0 && c0 < C) res.push_back({r0, c0}); } t = x; x = y; y = -t; } return res; } };
Github 同步地址:
https://github.com/grandyang/leetcode/issues/885
相似題目:
參考資料:
https://leetcode.com/problems/spiral-matrix-iii/
https://leetcode.com/problems/spiral-matrix-iii/discuss/158970/C%2B%2BJavaPython-112233-Steps