您的代码存在一些问题:
它不会以相同的方式对待遍历的四个方向。对于这四个方向,您有四个循环,但在某些情况下,<= 作为循环结束条件,在其他情况下,<,在某些情况下是负 1,在其他情况下不是。
它没有规定第一个或第二个内部循环何时打印所有元素,因此在某些情况下剩余的循环将打印已打印的元素。
外循环条件不检查是否还有需要遍历的列。仅测试这些行是不够的。
虽然您可以尝试修复您的代码,但我认为最好从头开始,考虑到解决方案应该在所有四个方向上都是对称的。这是一个重要的直观反应:点对称性。这将导致更少的代码和更少的错误。
您想遍历数组中的一个维度(行或列),直到到达数组的边界或已打印的元素。然后你想向右转 90°,一遍又一遍地重复完全相同的逻辑。因此,如果您的代码在这些不同的方向上看起来不同,则说明有问题。
我将分享两个实现。两者都将使用“当前”单元的概念,并让它以螺旋运动的方式移动。
第一个解决方案使用相同的代码处理沿行向后或向前移动,类似地,它有一段代码用于向前或向后遍历列。所以这个解决方案有两个内部循环,一个用于沿行遍历,另一个用于沿列遍历。行或列被遍历的方向保存在$direction变量中,在每次执行外循环时在1和-1之间翻转:
function _spiral(array $array) {
// No need to have the number of rows and columns passed as arguments:
// We can get that information from the array:
$rows = count($array);
$cols = count($array[0]);
// Set "current" cell to be outside array: it moves into it in first inner loop
$row = 0;
$col = -1;
$direction = 1; // Can be 1 for forward and -1 for backward
while ($rows > 0 and $cols > 0) {
// Print cells along one row
for ($step = 0; $step < $cols; $step++) {
$col += $direction;
print $array[$row][$col] . ' ';
}
// As we have printed a row, we have fewer rows left to print from:
$rows--;
// Print cells along one column
for ($step = 0; $step < $rows; $step++) {
$row += $direction;
print $array[$row][$col] . ' ';
}
// As we have printed a column, we have fewer columns left to print from:
$cols--;
// Now flip the direction between forward and backward
$direction = -$direction;
}
}
注意第一个内环和第二个内环之间的完美对称。
在第二种解决方案中,这种对称性的使用更进一步,以便仅用一个替换两个内部循环。为此,我们必须放弃对行和列使用单独的变量,并使用与维度相关的大小的概念:
function _spiral(array $array) {
// This version of the function aims to treat rows and columns in the same way,
// They are just another dimension, but all the logic is exactly the same:
// $size[] has the number of rows in $size[0] and number of columns in $size[1]
$size = Array(count($array), count($array[0]));
// $current[] has the current row in $current[0] and current column in $current[1]
$current = Array(0, -1);
// $direction[] has the current row-traversal direction in $direction[0]
// and column-traveral direction in $direction[1]
$direction = Array(1, 1);
$dimension = 0; // Which dimension to traverse along, can be 0 for row, 1 for column
while ($size[$dimension] > 0) {
// Switch dimension (row to column, column to row), to traverse along
$dimension = 1 - $dimension;
// Print one line along that dimension, in its current direction
for ($step = 0; $step < $size[$dimension]; $step++) {
$current[$dimension] += $direction[$dimension];
print $array[$current[0]][$current[1]] . ' ';
}
// As we have printed a line, we have fewer left to print from:
$size[1 - $dimension]--;
// Now flip the direction between forward and backward for this dimension:
$direction[$dimension] = -$direction[$dimension];
}
}
扩展版
一年多后应要求:这里有一个版本,可以选择从哪个角开始,以及是否逆时针而不是顺时针。这个函数不会打印结果,而是返回一个一维数组,带有螺旋序列。通过这种方式,您可以自己决定如何处理结果:打印它,或者……随便什么。
function spiral(array $array, $startRight = false, $startBottom = false,
$counterClockWise = false) {
// This version allows to select which corner to start from, and in which direction.
// $size[] has the number of rows in $size[0] and number of columns in $size[1]
$size = [count($array), count($array[0])];
// $direction[] has the current row-traversal direction in $direction[0]
// and column-traversal direction in $direction[1]
$direction = [$startBottom ? -1 : 1, $startRight ? -1 : 1];
// Which dimension to traverse along: false means row, true means column.
// Every one of the optional arguments will flip the first dimension to use:
$dimension = ($startBottom xor $startRight xor $counterClockWise);
// $current[] has the current row in $current[0] and current column in $current[1]
$current = [$startBottom * (count($array)-1), $startRight * (count($array[0])-1)];
// Go back one step, outside of the grid
$current[!$dimension] -= $direction[!$dimension];
while ($size[$dimension] > 0) {
// Switch dimension (row to column, column to row), to traverse along
$dimension = !$dimension;
// Print one line along that dimension, in its current direction
for ($step = 0; $step < $size[$dimension]; $step++) {
$current[$dimension] += $direction[$dimension];
$result[] = $array[$current[0]][$current[1]]; // store in new array
}
// As we have printed a line, we have fewer left to print from:
$size[!$dimension]--;
// Now flip the direction between forward and backward for this dimension:
$direction[$dimension] = -$direction[$dimension];
}
return $result; // Return the resulting spiral as a 1D array
}
看到它在eval.in上运行