[每日一題] 第二十一題:順時針列印矩陣

DRose發表於2020-08-02

輸入一個矩陣,按照從外向裡以順時針的順序依次列印出每一個數字。

示例 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]可以發現,順時針列印矩陣的順序是“從左向右,從上到下,從右向左,從下向上”迴圈。

  • 因此,考慮設定矩陣的“左,上,右,下”四個便捷,模擬以上矩陣遍歷順序。

[每日一題] 第二十一題:順時針列印矩陣

演算法流程

  1. 空值處理:matrix 為空時,直接返回空列表 [] 即可。

  2. 初始化: 矩陣 左、右、上、下 四個邊界 lrtb,用於列印的結果列表 res

  3. 迴圈列印: “從左向右,從上向下,從右向左,從下向上”四個方向迴圈,每個方向列印中做以下三件事(各方向的具體資訊見下表):

    1. 根據邊界列印,即將元素按順序新增至列表 res 尾部;
    2. 邊界向內收縮 1(代表已被列印);
    3. 判斷是否列印完畢(邊界是否相遇),若列印完畢則跳出。
  4. 返回值: 返回 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): 四個邊界 lrtb 使用常數大小的 額外 空間(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;
    }
}

個人理解

  1. 規律: 該解法有一個規律,就是順時針列印對應的是一個迴圈,這個迴圈就是從左到右,從上到下,從右到左,從下到上,通過該迴圈可以解決方向的問題,我們不必再控制方向如何變,我們只需要一個 while 迴圈,在條件滿足的情況下,依次執行上述各個方向遍歷,就是方向的控制。
  2. 邊界設定: left=0right=matrix[0].lengthtop=0bottom=matrix.length
  3. 需要定義一個返回結果陣列 result[],同時還需要定義一個索引下標,用來向陣列中寫資料使用,即 index=0
  4. 迴圈賦值: 我們應該怎樣迴圈賦值呢,以從左向右為例,我們需要找到左邊界和右邊界,即 leftright,從左向右依次遍歷即可,那麼我們怎麼確定是陣列中的哪個值呢?我們還需要知道我們位於哪一行,這時候就需要 top 引數了,通過 matrix[top][i] 我們就可以知道這是資料中的哪個值了。
  5. 判斷什麼邊界: 當我們按照一個方向迴圈遍歷完事之後,我們應該如何判斷邊界,判斷什麼邊界呢?以從左向右 為例,該方向遍歷完成之後,我們下一個方向應該是從上到下,所以我們應該判斷從上到下的邊界是否超過。
  6. 如何比較邊界:從左向右為例,我們應該比較上下邊界了,那麼怎樣才算超出邊界呢,top=bottom ?當 top=bottom 時說明此時應該為最後遍歷的一行,所以應該 top>bottom的時候超出邊界了。
  7. 二維陣列下標: 在這個過程中一定不弄反了座標,topbottom橫座標leftright縱座標

以下程式碼是按照自我理解寫的,簡化後就是上述程式碼:

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 協議》,轉載必須註明作者和本文連結

相關文章