题目描述
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
示例 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
给定代码
class Solution {
public int[] spiralOrder(int[][] matrix) {
}
}
题解一
循环解法,按层遍历,各种边界条件需要考虑,导致代码杂乱无章。不推荐使用。
class Solution {
public int[] spiralOrder(int[][] matrix) {
int lineWidth = matrix.length;
if (lineWidth == 0) {
return new int[] {};
}
int lineLen = matrix[0].length;
int [] result = new int[lineWidth * lineLen];
int count = 0;
int layerCount = (Math.min(lineLen, lineWidth) + 1) / 2;
for (int i = 0 ; i < layerCount ; i++)
{
if (lineWidth == 1) {
for (int j = i ; j < i + lineLen ; j++) {
result[count++] = matrix[i][j];
}
break;
} else if (lineLen == 1) {
for (int j = i ; j < i + lineWidth ; j++) {
result[count++] = matrix[j][i + lineLen - 1];
}
break;
}
for (int j = i ; j < i + lineLen ; j++) {
result[count++] = matrix[i][j];
}
for (int j = i + 1 ; j < i + lineWidth ; j++) {
result[count++] = matrix[j][i + lineLen - 1];
}
for (int j = i + lineLen - 2 ; j > i ; j--) {
result[count++] = matrix[i + lineWidth - 1][j];
}
for (int j = i + lineWidth - 1 ; j > i ; j--) {
result[count++] = matrix[j][i];
}
lineLen -= 2;
lineWidth -= 2;
}
return result;
}
}
时间复杂度:
O
(
V
)
O(V)
O(V)。
数组中的每个元素操作了一次。
空间复杂度:
O
(
1
)
O(1)
O(1)。
除了答案集空间开销为
O
(
V
)
O(V)
O(V),其余辅助空间都为常数级。这里答案集不算进去是因为答案集的元素没有调用关系,仅仅作为最后返回的结果。
题解二
递归解法,递归参数需要一个方向参数,代表这个元素接下来往哪走。
假设当前方向为右,那么判断右边元素是否超界、是否被访问过。如果没有超界且没有被访问过,则递归转移到右边的节点。
如果超界了,或者以及访问过,那么就得改变方向了,继续判断是否能向下转弯。
虽然代码量类似,但递归思路更清晰。
class Solution {
private int [][] matrix;
private int [] result;
private int [][] checked;
private int width = 0;
private int len = 0;
private int count = 0;
public int[] spiralOrder(int[][] matrix) {
if (matrix.length == 0) {
return new int[] {};
}
this.matrix = matrix;
this.len = matrix[0].length;
this.width = matrix.length;
this.result = new int[len * width];
this.checked = new int[width][len];
// 起始点为[0,0],向右走
circle(0, 0, 1);
return result;
}
// direction为方向
// 1 -> 右,2 -> 下,3 -> 左,4 -> 上
private void circle(int x, int y, int direction)
{
// 将当前节点添加到结果集,并标记已访问
// 这里保证传进来的坐标是合法的
result[count++] = matrix[x][y];
checked[x][y] = 1;
if (direction == 1)
{
// 判断是否能继续向右走,如果不能,判断是否能向下转弯
if (y + 1 < len && checked[x][y + 1] == 0) {
circle(x, y + 1, 1);
} else if (x + 1 < width && checked[x + 1][y] == 0) {
circle(x + 1, y, 2);
}
}
else if (direction == 2)
{
// 判断是否能继续向下走,如果不能,判断是否能向左转弯
if (x + 1 < width && checked[x + 1][y] == 0) {
circle(x + 1, y, 2);
} else if (y - 1 >= 0 && checked[x][y - 1] == 0) {
circle(x, y - 1, 3);
}
}
else if (direction == 3)
{
// 判断是否能继续向左走,如果不能,判断是否能向上转弯
if (y - 1 >= 0 && checked[x][y - 1] == 0) {
circle(x, y - 1, 3);
} else if (x - 1 >= 0 && checked[x - 1][y] == 0) {
circle(x - 1, y, 4);
}
}
else
{
// 判断是否能继续向上走,如果不能,判断是否能向右转弯
if (x - 1 >= 0 && checked[x - 1][y] == 0) {
circle(x - 1, y, 4);
} else if (y + 1 < len && checked[x][y + 1] == 0) {
circle(x, y + 1, 1);
}
}
}
}
时间复杂度:
O
(
V
)
O(V)
O(V)。
数组中的每个元素操作了一次。
空间复杂度:
O
(
V
)
O(V)
O(V)。
checked
数组开销为
O
(
V
)
O(V)
O(V),其余辅助空间都为常数级。