Как повернуть матрицу на 90 градусов против часовой стрелки в Java?
Я пытаюсь разобраться с проблемами в книге "Взлом кодирования". Один из вопросов просит меня повернуть матрицу на 90 градусов по часовой стрелке. Теперь, пытаясь укрепить мое понимание поворота матрицы, я попытался встать перед новой проблемой: попытаться повернуть матрицу на 90 градусов против часовой стрелки (в другом направлении).
Я попытался пройти через слои квадратной матрицы, внешний слой, итерируя весь путь до внутреннего слоя и поворачивая все индексы каждой стороны "квадрата" один за другим. Это в основном то, что реализовало решение Гейл Лакман Макдауэлл, но в другом направлении.
public static void rotateMatrix(int[][] matrix) {
if(matrix.length == 0) {
return;
}
for(int i = 0; i < matrix.length/2; i++) {
int top = i;
int bottom = matrix.length-1-i;
for(int j = top; j < bottom; j++) {
int temp = matrix[top][j];
matrix[top][j] = matrix[j][matrix.length-1-j];
matrix[j][matrix.length-1-j] = matrix[bottom][j];
matrix[bottom][j] = matrix[j][matrix.length-1-bottom];
matrix[j][matrix.length-1-bottom] = temp;
}
}
}
Я ожидал результата образца матрицы
[[1,2,3],[4,5,6],[7,8,9]]
быть [[3,6,9],[2,5,8],[1,4,7]
, но мой код привел в [[1,5,7],[2,8,6],[3,4,9]]
, Где в моем коде ошибка / расхождение?
3 ответа
Если вы нарисуете матрицу для визуализации, вы увидите, что некоторые ваши индексы отключены. Например, вместо matrix.length-1, вы должны использовать bottom в ваших обновлениях, потому что размер квадрата слоя будет уменьшаться по мере увеличения i. Другая ошибка заключается в том, что во втором обновлении вы должны иметь:
matrix[j][bottom] = matrix[bottom][bottom - (j - top)];
вместо:
matrix[j][bottom] = matrix[bottom][j];
Это связано с тем, что в нижней строке слоя индексы начинаются с последнего столбца и перемещаются назад к первому столбцу. j - top показывает, как далеко вы находитесь в верхнем ряду вашего слоя. После составления матрицы я обнаружил, что правильные обновления выглядят следующим образом:
public class matrix {
public static void main(String[] args) {
int n = 5;
int[][] a = new int[n][n];
for (int i = 0; i < n; i ++) {
for (int j = 0; j < n; j ++) {
a[i][j] = i * n + j + 1;
}
}
rotateMatrix(a);
for (int i = 0; i < a.length; i ++) {
for (int j = 0; j < a[0].length; j ++) {
System.out.printf("%3d", a[i][j]);
}
System.out.println();
}
}
public static void rotateMatrix(int[][] matrix) {
if (matrix.length == 0) {
return;
}
for (int i = 0; i < matrix.length / 2; i++) {
int top = i;
int bottom = matrix.length - 1 - i;
for (int j = top; j < bottom; j++) {
int temp = matrix[top][j];
matrix[top][j] = matrix[j][bottom];
matrix[j][bottom] = matrix[bottom][bottom - (j - top)];
matrix[bottom][bottom - (j - top)] = matrix[bottom - (j - top)][top];
matrix[bottom - (j - top)][top] = temp;
}
}
}
}
Выход:
5 10 15 20 25
4 9 14 19 24
3 8 13 18 23
2 7 12 17 22
1 6 11 16 21
Поворот матрицы на 90 градусов аналогичен транспонированию. Индексы
[i][j]
стали
[j][i]
, но индексы одной из его сторон становятся равными
the length of the side, minus 1, minus the current index of the side
. Индексы начинаются с 0.
int m = 5;
int n = 4;
int[][] arr1 = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16},
{17, 18, 19, 20}};
int[][] arr2 = new int[n][m];
int[][] arr3 = new int[n][m];
IntStream.range(0, m).forEach(i ->
IntStream.range(0, n).forEach(j -> {
// turn matrix 90º clockwise ⟳
arr2[j][m - 1 - i] = arr1[i][j];
// turn matrix 90º anticlockwise ⟲
arr3[n - 1 - j][i] = arr1[i][j];
}));
// Output to the markdown table:
String[] matrices = Stream.of(arr1, arr2, arr3)
.map(arr2d -> Arrays.stream(arr2d)
.map(arr -> Arrays.stream(arr)
.mapToObj(i -> String.format("%2d", i))
.toArray())
.map(Arrays::toString)
.collect(Collectors.joining("<br>")))
.toArray(String[]::new);
System.out.println("| original matrix | turn matrix 90º ⟳ | turn matrix 90º ⟲ |");
System.out.println("|---|---|---|");
System.out.println("|<pre>" + String.join("</pre>|<pre>", matrices) + "</pre>|");
Вы работаете с одним экземпляром матрицы, устанавливаете значения в матрице и одновременно читаете старые значения, что, вероятно, вызывает вашу проблему.
Заставить функцию возвращать новую матрицу облегчит вашу работу. Ваш код может быть таким:
public static int[][] rotateMatrix(int[][] m) {
if(m.length == 0) return new int[0][0];
int rows = m.length, cols = m[0].length;
int[][] result = new int[cols][rows];
for(int row = 0; row < cols; row++) {
for(int col = 0; col < rows; col++) {
result[row][col] = m[col][rows - row - 1];
}
}
return result;
}
Я бы также инкапсулировал int[][]
массив в классе для обеспечения неизменности.