题干
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。例如,如果输入如下矩阵:
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, 0)
,第二圈的起点就是(1, 1)
,依次类推,第n圈的起点就是 (n-1, n-1)
,又由于我们每循环一圈,都可能会输出两行两列的数据,所以我们现在来考虑下最后一圈起点坐标和行数、列数之间的关系,例如:如果是 8X8
的矩阵,则最后一圈的坐标是(3, 3)
,行数大于两倍的行坐标,即8>3*2
,如果是 9X9
的矩阵,则最后一圈的坐标是 (4, 4)
,行数大于两倍的行坐标,即9>4*2
,列数同理,由此我们可以分析得出,只要行数和列数都大于最后一圈的起点坐标的行和列,则还需要循环一圈。
对于第二个问题,我们需要考虑一些特殊情况了,对于行列相同的矩阵,每一圈循环都会按照从左到右,从上到下,从右到左,从下到上的四个步骤完成打印,而对于一些不规则的矩阵,如行数小于列数,行数大于列数时,需要特别分析一下,有可能出现缺少后面几步的情况。
- 如果需要执行从上到下的打印,需要循环的结束行号大于开始行号
- 如果需要执行从右到左的打印,需要循环的结束行号大于开始行号,且结束列号大于开始列号
- 如果需要执行从下到上的打印,不仅仅需要循环的结束号大于开始行号,而需要结束行号-开始行号>=2,且结束列号大于开始列号
到此,上面的两个问题就分析完了,可以代码实现了。
代码实现
<?php
/**
* @param array $arr 二维数组
* @param int $columns 列数
* @param int $rows 行数
*/
function printMatrixClockwisely(array $arr, int $columns, int $rows)
{
if ($arr == null || $columns == 0 || $rows == 0) {
return;
}
$start = 0;
while ($columns > $start * 2 && $rows > $start * 2) {
printMatrixInCircle($arr, $columns, $rows, $start);
$start++;
}
}
/**
* @param array $arr 二维数组
* @param int $columns 列数
* @param int $rows 行数
* @param int $start 圈号
*/
function printMatrixInCircle(array $arr, int $columns, int $rows, int $start)
{
// 从0开始,需要额外减1
$endRow = $rows - $start - 1;
$endColumn = $columns - $start - 1;
// 从左至右输出
for ($i = $start; $i <= $endColumn; $i++) {
$num = $arr[$start][$i];
printNum($num);
}
// 从上至下输出
if ($endRow > $start) {
for ($i = $start + 1; $i <= $endRow; $i++) {
$num = $arr[$i][$endColumn];
printNum($num);
}
}
// 从右至左输出
if ($endRow > $start && $endColumn > $start) {
for ($i = $endColumn - 1; $i >= $start; $i--) {
$num = $arr[$endRow][$i];
printNum($num);
}
}
// 从下至上输出
if ($endColumn > $start && $endRow - $start > 1) {
for ($i = $endRow - 1; $i > $start; $i--) {
$num = $arr[$i][$start];
printNum($num);
}
}
}
function printNum($num)
{
printf('%3d', $num);
}
$arr = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]];
printMatrixClockwisely($arr, 4, 4);