輸入一個矩陣,按照從外向裡以順時針的順序依次列印出每一個數字。
示例 1:
輸入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
輸出:[1,2,3,6,9,8,7,4,5]
示例 2:
輸入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
輸出:[1,2,3,4,8,12,11,10,9,5,6,7]
限制:
0 <= matrix.length <= 100
0 <= matrix[i].length <= 100
方法一:模擬、設定邊界
解題思路
根據題目示例
matrix = [[1,2,3],[4,5,6],[7,8,9]]
的對應輸出[1,2,3,6,9,8,7,4,5]
可以發現,順時針列印矩陣的順序是“從左向右,從上到下,從右向左,從下向上”迴圈。
- 因此,考慮設定矩陣的“左,上,右,下”四個便捷,模擬以上矩陣遍歷順序。
演算法流程:
空值處理: 當
matrix
為空時,直接返回空列表[]
即可。初始化: 矩陣 左、右、上、下 四個邊界
l
,r
,t
,b
,用於列印的結果列表res
。迴圈列印: “從左向右,從上向下,從右向左,從下向上”四個方向迴圈,每個方向列印中做以下三件事(各方向的具體資訊見下表):
- 根據邊界列印,即將元素按順序新增至列表
res
尾部; - 邊界向內收縮 1(代表已被列印);
- 判斷是否列印完畢(邊界是否相遇),若列印完畢則跳出。
- 根據邊界列印,即將元素按順序新增至列表
返回值: 返回
res
即可。
列印方向 | 1. 根據邊界列印 | 2. 邊界向內收縮 | 3. 是否列印完畢 |
---|---|---|---|
從左向右 | 左邊界l ,右邊界 r | 上邊界 t 加 11 | 是否 t > b |
從上向下 | 上邊界 t ,下邊界b | 右邊界 r 減 11 | 是否 l > r |
從右向左 | 右邊界 r ,左邊界l | 下邊界 b 減 11 | 是否 t > b |
從下向上 | 下邊界 b ,上邊界t | 左邊界 l 加 11 | 是否 l > r |
複雜度分析:
時間複雜度 O(MN) : M, N 分別為矩陣行數和列數。
空間複雜度 O(1): 四個邊界 l
,r
,t
,b
使用常數大小的 額外 空間(res
為必須使用的空間)。
程式碼
Java 程式碼利用了
++
操作的便利性
res[x++]
等價於先給res[x]
賦值,再給x
自增 1;++t > b
等價於先給t
自增 1,再判斷t > b
邏輯表示式。
class Solution {
public int[] spiralOrder(int[][] matrix) {
if(matrix.length == 0) return new int[0];
int l = 0, r = matrix[0].length - 1, t = 0, b = matrix.length - 1, x = 0;
int[] res = new int[(r + 1) * (b + 1)];
while(true) {
for(int i = l; i <= r; i++) res[x++] = matrix[t][i]; // left to right.
if(++t > b) break;
for(int i = t; i <= b; i++) res[x++] = matrix[i][r]; // top to bottom.
if(l > --r) break;
for(int i = r; i >= l; i--) res[x++] = matrix[b][i]; // right to left.
if(t > --b) break;
for(int i = b; i >= t; i--) res[x++] = matrix[i][l]; // bottom to top.
if(++l > r) break;
}
return res;
}
}
個人理解
- 規律: 該解法有一個規律,就是順時針列印對應的是一個迴圈,這個迴圈就是從左到右,從上到下,從右到左,從下到上,透過該迴圈可以解決方向的問題,我們不必再控制方向如何變,我們只需要一個
while
迴圈,在條件滿足的情況下,依次執行上述各個方向遍歷,就是方向的控制。 - 邊界設定:
left=0
,right=matrix[0].length
,top=0
,bottom=matrix.length
。 - 需要定義一個返回結果陣列
result[]
,同時還需要定義一個索引下標,用來向陣列中寫資料使用,即index=0
。 - 迴圈賦值: 我們應該怎樣迴圈賦值呢,以從左向右為例,我們需要找到左邊界和右邊界,即
left
和right
,從左向右依次遍歷即可,那麼我們怎麼確定是陣列中的哪個值呢?我們還需要知道我們位於哪一行,這時候就需要top
引數了,透過matrix[top][i]
我們就可以知道這是資料中的哪個值了。 - 判斷什麼邊界: 當我們按照一個方向迴圈遍歷完事之後,我們應該如何判斷邊界,判斷什麼邊界呢?以從左向右 為例,該方向遍歷完成之後,我們下一個方向應該是從上到下,所以我們應該判斷從上到下的邊界是否超過。
- 如何比較邊界: 以從左向右為例,我們應該比較上下邊界了,那麼怎樣才算超出邊界呢,
top=bottom
?當top=bottom
時說明此時應該為最後遍歷的一行,所以應該top>bottom
的時候超出邊界了。 - 二維陣列下標: 在這個過程中一定不弄反了座標,
top
,bottom
是橫座標
,left
,right
是縱座標
。
以下程式碼是按照自我理解寫的,簡化後就是上述程式碼:
class Solution {
public int[] spiralOrder(int[][] matrix) {
if (matrix.length == 0 || matrix[0].length == 0) {
return new int[0];
}
int left = 0;
int right = matrix[0].length - 1;
int top = 0;
int bottom = matrix.length - 1;
int length = matrix.length*matrix[0].length;
int[] result = new int[length];
int index = 0;
while (true) {
//從左向右
for (int i=left; i<=right; i++) {
result[index] = matrix[top][i];
index++;
}
top++;
if (top > bottom) {
break;
}
//從上到下
for (int i=top; i<=bottom; i++) {
result[index] = matrix[i][right];
index++;
}
right--;
if(left > right) {
break;
}
//從右到左
for (int i=right; i>=left; i--) {
result[index] = matrix[bottom][i];
index++;
}
bottom--;
if(top > bottom) {
break;
}
//從下到上
for( int i=bottom; i>=top; i--) {
result[index] = matrix[i][left];
index++;
}
left++;
if (left > right) {
break;
}
}
return result;
}
}
來源
作者:jyd
連結:leetcode-cn.com/problems/shun-shi-...
來源:力扣(LeetCode)
本作品採用《CC 協議》,轉載必須註明作者和本文連結