基本思路:
这道题目的话属于一道模拟题,只需要找出输出的规则和边界终止条件即可。

方法一:按时钟指针转动规则

方式一我们可以按照时钟中指针的转动方向来模拟这道题目的输出结果。
我们从最上面开始遍历,接着到边的时候就向下遍历,然后向左向上遍历,当一圈遍历结束的时候则进入里圈进行遍历。下面直接贴出代码并有相应的题解。

import java.util.*;

//  1 2 3    螺旋 1 2 3 6 9 8 7 4 5
//  4 5 6
//  7 8 9 
public class Solution {
    public ArrayList<integer> spiralOrder(int[][] matrix) {
        ArrayList<integer> res = new ArrayList<>();
        if(matrix.length == 0)
            return res;
        // 定义四个指针,并且充当边界限制的作用
        int top = 0, bottom = matrix.length-1;
        int left = 0, right = matrix[0].length-1;

        while( top < (matrix.length+1)/2 && left < (matrix[0].length+1)/2 ){
            //上面  左到右
            for(int i = left; i <= right; i++){
                res.add(matrix[top][i]);
            }

            //右边 上到下
            for(int i = top+1; i <= bottom; i++){
                res.add(matrix[i][right]);
            }

            //下面  右到左
            for(int i = right-1; top!=bottom && i>=left; i--){
                res.add(matrix[bottom][i]);
            }

            //左边 下到上
            for(int i = bottom-1; left!=right && i>=top+1; i--){
                res.add(matrix[i][left]);
            }
            // 遍历完一圈之后,所有往里面靠
            ++top;
            --bottom;
            ++left;
            --right;
        }
        return res;
    }
}

图解:
图片说明

方法二:按照圈进行模拟

方法一的话是进行旋转打印,那么方法二的话我们还可以一圈一圈打印,其实跟方法一的代码很类似,但是是两种不同的想法,在于你对解决方式的理解不同。
其实就是根据下面的圈,根据定义的两个点,左上角和右下角去进行圈的遍历,两个点的x,y坐标其实跟方法一的left,right,top,bottom是起到一样作用的,只是这是另外一种思想。
图片说明
我们看代码吧~

import java.util.*;

//  1 2 3    螺旋 1 2 3 6 9 8 7 4 5
//  4 5 6
//  7 8 9 
public class Solution {
    public ArrayList<Integer> spiralOrder(int[][] matrix) {
        ArrayList<Integer> res = new ArrayList<>();、
        // 进行数组的判空
        if(matrix.length == 0)
            return res;
        // 找到整个数组的 右边界 和 下边界
        int m = matrix.length, n = matrix[0].length;
        // 两个点(0,m-1)  (0,n-1)
        circle(matrix, 0, 0, m - 1, n - 1, res);
        return res;

    }
    // 遍历 以 (x1, y1) 作为左上角,(x2, y2) 作为右下角形成的「圈」
    void circle(int[][] matrix, int x1, int y1, int x2, int y2, List<Integer> ans) {
        // 此时则已经交叉所以退出
        if (x2 < x1 || y2 < y1) return;

        // 只有一行时,按「行」遍历
        if (x1 == x2) {
            for (int i = y1; i <= y2; i++) ans.add(matrix[x1][i]);
            return;
        }
        // 只有一列时,按「列」遍历
        if (y1 == y2) {
            for (int i = x1; i <= x2; i++) ans.add(matrix[i][y2]);
            return;
        }

        // 遍历当前「圈」
        // 从左往右
        for (int i = y1; i < y2; i++) ans.add(matrix[x1][i]);
        // 从上往下
        for (int i = x1; i < x2; i++) ans.add(matrix[i][y2]);
        // 从右往左
        for (int i = y2; i > y1; i--) ans.add(matrix[x2][i]);
        // 从下往上
        for (int i = x2; i > x1; i--) ans.add(matrix[i][y1]);

        // 往里收一圈,继续递归遍历
        circle(matrix, x1 + 1, y1 + 1, x2 - 1, y2 - 1, ans);
    }
}

复杂度分析:
时间复杂度:O(m*n),其实就是双重循环,两个循环的次数取决于二维数组的行列长度。
空间复杂度:O(1),除了必要的返回输出数组以外,空间复杂度是常数。没有使用额外的空间。