模拟法

  • 首先,需要确定定义边界的规则,从而确定模拟的区间,比如采用左闭右开,左闭右闭等。本题建议采用左闭右开,也就是起点闭合,终点打开。
  • 其次,循环次数也很重要,用来确定模拟什么时候结束。本题没转一圈是走2行和2列,因此模拟次数为行数和列数中最小值的一半。
  • 如果为奇数行或奇数列,每次走2行2列,最后会剩下1行或1列,因此最后需要模拟打印剩下的1行或一列。
import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> spiralOrder(int[][] matrix) {
        ArrayList<Integer> res = new ArrayList<>();
        if(matrix == null || matrix.length == 0)
            return res;
        int m = matrix.length, n = matrix[0].length;
        int loop = Math.min(m / 2, n /2); // 循环次数
        int startx = 0, starty = 0;
        int offset = 1; // 偏移量
        int i,j;
        // 参考代码随想录:区间[起点,终点),左闭右开
        for(int c = 0; c < loop; c++){
			i = startx;
			j = starty;
			// 上
			while(j < starty + n - offset){
				res.add(matrix[i][j]);
				++j;
			}
			// 右
			while(i < startx + m - offset){
				res.add(matrix[i][j]);
                ++i;
			}
			// 下
			while(j > starty){
				res.add(matrix[i][j]);
				j--;
			}
			// 左
			while(i > startx){
				res.add(matrix[i][j]);
				i--;
			}
			startx++;
			starty++;
			offset += 2; //因为startx和starty也加了1,所以计算边界时需要将其减掉
        }
		if(Math.min(m, n) % 2 == 1){ // 每次走2行2列,所以奇数行或奇数列最后会剩下一行或一列
			i = startx;
			j = starty;
			if(m <= n){
				// 剩下一行
				for(; j <= starty + n - offset; j++){
					res.add(matrix[i][j]);
				}
			} else {
				// 剩下一列
				for(; i <= startx + m - offset; ++i)
					res.add(matrix[i][j]);
			}
		}
		return res;
    }
}