问题
顺时针循环打印一个矩阵元素。
https://www.geeksforgeeks.org/print-a-given-matrix-in-spiral-form/
难点:如何控制下一步该往哪里走?
思路
想法一:如何控制下一步?下一步是由当前方向决定的。所以最直观的想法就是维护一个方向变量,然后建立一个偏移量的二维数组,第一维传入的方向,大小为4,第二维是x和y方向的前进量,大小为2。然后我们就根据方向来获取下一步移动的偏移量,如果碰壁,就修改方向,方向的修改是一个从大小为4的循环数组中轮流取值的过程。这个思路是可行的。当然还需要判定停止条件,可以用一个辅助数组记录哪些遍历过,如果遍历到一个已经遍历过的元素,就跳出,这是一种思路。
想法二:
想法一是可行的,但是其实可以省去方向变量和标记的过程,思考的模式变一下。
每一次x和y变化的坐标只有一个,所以我们只需要一个遍历指针(其实是变量);
整个过程可以看成是多轮遍历,每一轮包括四个方向,绕一圈;
也就是抽象为:
while(){
for()
for()
for()
for()
}
每一个内部的for,都会限定遍历的范围,遍历完就更新边界值。还要想好跳出的条件,就是遍历完一行或者一列,导致下一次没有空余的行或者列遍历了,也就是for之前判定一下行号或者列号的最大值是否小于最小值,如果是就break。那是不是每一个for循环都要判定?都判定肯定没问题,如果想要精简代码,只需要判定一个列的遍历和一个行的遍历即可。因为总会走到这个判定里。并且每一个for循环内部也不会受影响,因为for内部有条件限制。
代码
public static void rotate(int[][] array) {
//遍历指针
int i;
//边界
int l = 0, k = 0, m = array.length - 1, n = array[0].length - 1;
//主循环
while (true) {
//遍历上面的行
for (i = k; i <= n; i++) {
System.out.println(array[l][i]);
}
//遍历完修改行的最小边界
l ++;
//遍历右侧的列
for (i = l; i <= m; i++){
System.out.println(array[i][n]);
}
//遍历完修改列的右边界
n --;
//检测行是否遍历完了,如果碰上了,说明该退出
if (l > m) {
break;
}
//遍历下面的行
for (i = n; i >= k; i--) {
System.out.println(array[m][i]);
}
//遍历完修改行的最大边界
m--;
//检测列是否遍历完了,如果碰上了,说明该退出
if (k > n) {
break;
}
//遍历左侧的列
for (i = m; i >= l; i--) {
System.out.println(array[i][k]);
}
//遍历完修改列的左边界
k++;
}
}