54. 螺旋矩阵

题目

原题链接:https://leetcode-cn.com/problems/spiral-matrix/

给你一个mn列的矩阵matrix,请按照顺时针螺旋顺序,返回矩阵中的所有元素。

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]

解题思路

可以将矩阵看成若干层,首先输出最外层的元素,其次输出次外层的元素,直到输出最内层的元素。
定义矩阵的第\(k\)层:例如,下图矩阵最外层元素都是第\(1\)层,次外层元素都是第\(2\)层,剩下的元素都是第\(3\)

[[1, 1, 1, 1, 1, 1, 1],
 [1, 2, 2, 2, 2, 2, 1],
 [1, 2, 3, 3, 3, 2, 1],
 [1, 2, 2, 2, 2, 2, 1],
 [1, 1, 1, 1, 1, 1, 1]]

对于每层,从左上方开始以顺时针的顺序遍历所有元素。假设当前层的左上角位于$ (\textit{top}, \textit{left})$,右下角位于 \((\textit{bottom}, \textit{right})\),按照如下顺序遍历当前层的元素

  • 从左到右遍历上侧元素,依次为 \((\textit{top}, \textit{left})\)\(\rightarrow\)\((\textit{top}, \textit{right})\)

  • 从上到下遍历右侧元素,依次为\((\textit{top} + 1, \textit{right})\)\(\rightarrow\)\((\textit{bottom}, \textit{right})\)

  • 如果\(\textit{left} < \textit{right}\)\(\textit{top} < \textit{bottom}\),则从右到左遍历下侧元素,依次为\((\textit{bottom}, \textit{right} - 1)\)\(\rightarrow\)\((\textit{bottom}, \textit{left})\),以及从下到上遍历左侧元素,依次为\((\textit{bottom}-1, \textit{left})\)\(\rightarrow\) \((\textit{top} + 1, \textit{left})\)

遍历完当前层的元素之后,将\(\textit{left}\)\(\textit{top}\)分别增加\(1\),将\(\textit{right}\)\(\textit{bottom}\)分别减少\(1\),进入下一层继续遍历,直到遍历完所有元素为止。

代码实现

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

/**
 * 54.螺旋矩阵
 * 按照顺时针螺旋顺序,返回m*n矩阵中的所有元素
 * @author chenzufeng
 */
public class No54_SpiralMatrix {
    public static void main(String[] args) {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            String[] info = reader.readLine().split(" ");
            int rows = Integer.parseInt(info[0]);
            int columns = Integer.parseInt(info[1]);
            int[][] matrix = new int[rows][columns];

            for (int i = 0; i < rows; i++) {
                String[] rowStr = reader.readLine().split(",");
                for (int j = 0; j < columns; j++) {
                    matrix[i][j] = Integer.parseInt(rowStr[j]);
                }
            }

            for (int i : spiralOrder(matrix)) {
                System.out.print(i + ",");
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static List<Integer> spiralOrder(int[][] matrix) {
        List<Integer> result = new ArrayList<>();
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return result;
        }

        // 初始化行和列,上下左右index
        int rows = matrix.length, columns = matrix[0].length;
        int left = 0, right = columns - 1, top = 0, bottom = rows - 1;

        while (left <= right && top <= bottom) {
            // 1.顶部行——从左到右,列column在变,边界为left到right
            for (int column = left; column <= right; column++) {
                result.add(matrix[top][column]);
            }

            // 2.右边列——从上到下,行row在变,边界为top+1到bottom
            for (int row = top + 1; row <= bottom; row++) {
                result.add(matrix[row][right]);
            }

            /*
             * 如果只有一行(top == bottom)或者一列(left == right),前两步则已经完成遍历
             * 否则,底部行——从右往左遍历;左边列——从下往上遍历
             */
            if (top < bottom && left < right) {
                // 3.底部行——从右往左遍历:列column在变,边界为right-1到left
                for (int column = right - 1; column >= left; column--) {
                    result.add(matrix[bottom][column]);
                }

                // 4.左边列——从下往上遍历,行row在变,边界为bottom-1到top
                for (int row = bottom - 1; row > top; row--) {
                    result.add(matrix[row][left]);
                }
            }

            // 5.一层遍历结束,准备遍历下一层,先定位
            left++;
            right--;
            top++;
            bottom--;
        }
        return result;
    }
}

复杂度分析

时间复杂度:\(O(mn)\),其中\(m\)\(n\)分别是输入矩阵的行数和列数。矩阵中的每个元素都要被访问一次。

空间复杂度:\(O(1)\),除了输出数组以外,空间复杂度是常数。

posted @ 2021-03-08 16:28  chenzufeng  阅读(163)  评论(0编辑  收藏  举报