描述

剑指offer JZ29 顺时针打印矩阵
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵:
[[1,2,3,4],
[5,6,7,8],
[9,10,11,12],
[13,14,15,16]]
则依次打印出数字
[1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10]
数据范围:
0 <= matrix.length <= 100
0 <= matrix[i].length <= 100

方法一:设置方向的优先级,并且单独考虑特殊情况进行遍历

思路:由于需要顺时针遍历矩阵,我们可以直观想到方向的优先级:右、下、左、上。我们可以通过标记已经遍历过的数字,每次都按顺序判断这四个方位,在前一个行不通时才会走下一个,大体实现顺时针遍历。但是存在一种特殊情况,就是在需要向上遍历的时候,由于是需要先判断右方向,所以遍历方向会向右走而不向上,这个时候我们可以在判断四个方向之前再加入一个条件:即在右方和上方都可通行的时候,优先向上走,即可解决。
代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import java.util.*;
import java.util.ArrayList;
public class Solution {
//标记位置是否已遍历
boolean[][] flags;

// 此方法用于根据优先级选择方向
public ArrayList<Integer> printMatrix(int [][] matrix) {
ArrayList<Integer> list = new ArrayList<>();
//先判断特殊情况
if (matrix.length==0 || matrix[0].length==0) return list;
//初始化标记数组
flags = new boolean[matrix.length][matrix[0].length];
int x = 0;
int y = 0;

//循环遍历
while(true) {
flags[x][y] = true;
list.add(matrix[x][y]);
//如果上方和右方同时可通行,优先往上走
if (checkAuth(x, y+1) && checkAuth(x-1, y)) x--;
//右方能通行
else if (checkAuth(x, y+1)) y++;
//下方能通行
else if (checkAuth(x+1, y)) x++;
//左方能通行
else if (checkAuth(x, y-1)) y--;
//上方能通行
else if (checkAuth(x-1, y)) x--;
//无路可走,返回集合
else return list;
}
}
//通过数字的坐标判断此点能不能通行
public boolean checkAuth(int x, int y) {
if (x < 0 || x > flags.length-1 || y < 0 || y > flags[0].length-1 || flags[x][y]) return false;
return true;
}
}

方法二:设置边界条件,经过遍历循环实现

思路:设置上下左右四种边界,每进行一次遍历,就将对应的边界改变,当边界冲突的时候退出循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Solution {
public ArrayList<Integer> printMatrix(int [][] matrix) {
ArrayList<Integer> list = new ArrayList<>();
if (matrix.length==0 || matrix[0].length==0) return list;
//初始化四条边界。
int top = 0;
int left = 0;
int bottom = matrix.length-1;
int right = matrix[0].length-1;
//边界条件冲突时,退出循环
while (top <= bottom && left <= right) {
//第一次循环,从左到右
for (int i = left; i <= right; i++) list.add(matrix[top][i]);
top++;
//上边界在下边界之下,遍历结束,退出循环
if (top > bottom) break;
//后面的也是一样的道理,分别时从上往下,从左往右,从下往上,并且每一次都需要判断遍历是否结束。
for (int i = top; i <= bottom; i++) list.add(matrix[i][right]);
right--;
if (left > right) break;
for (int i = right; i >= left; i--) list.add(matrix[bottom][i]);
bottom--;
if (top > bottom) break;
for (int i = bottom; i >= top; i--) list.add(matrix[i][left]);
left++;
if (left > right) break;
}
return list;
}
}