моя задача - сдвинуть строки массива на фиксированную величину «сдвига» и заполнить сдвинутые строки нулями:
Например, массив:
1 1 1 1 1
1 1 3 1 1
1 6 2 1 4
1 1 1 8 1
1 1 1 1 1
сдвиг на 2 должен привести к:
0 0 0 0 0
0 0 0 0 0
1 1 1 1 1
1 1 3 1 1
1 6 2 1 4
public static void main(String args[]) {
int[][] a = { { 1, 1, 1, 1, 1 }, { 1, 1, 3, 1, 1 }, { 1, 6, 2, 1, 4 }, { 1, 1, 1, 8, 1 }, { 1, 1, 1, 1, 1, } };
System.out.println(Arrays.deepToString(move(a, 2)));
}
public static int[][] move(int[][] a, int shift) {
for (int i = a.length - 1; i >= shift; i--) {
a[i] = a[i - shift];
}
for (int i = 0; i < shift; i++) {
for (int j = 0; j < a[0].length; j++) {
a[i][j] = 0;
}
}
return a;
}
Мой результат:
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [1, 6, 2, 1, 4]]
Если я распечатаю свой массив после первого цикла for, это правильно, я не понимаю, почему второй цикл for меняет строки 2 и 3.
Для подобных проблем вам может помочь записать ответы простыми словами (или псевдокодом), а затем закодировать решение на основе этого. Кроме того, вы можете сначала попытаться найти решение для копирования массива. Создайте новый массив, заполненный нулями, затем скопируйте каждую строку исходного массива с индексом 0 в новый массив, начиная со смещения (т. е. +2), пока вы не сможете больше копировать строки. Затем, как только это решение заработает, создайте решение «на месте», в котором вы перезапишете строки. Как правило, второй подход более сложен, чем первый. Так что при обучении такой подход должен помочь.
Если вы хотите избежать ссылки на всю строку и возникновения этой проблемы, вы можете скопировать отдельные элементы в каждой строке, проходя столбец за столбцом, вместо этого с помощью вложенного цикла for.




Когда вы копируете строку из одной позиции в другую, вы копируете ссылку на ту же строку в памяти (проверьте это). Вы должны учитывать это, чтобы ваш код работал правильно:
public static int[][] move(int[][] a, int shift) {
int rows = a.length;
int cols = a[0].length;
// New array to store the result
int[][] result = new int[rows][cols];
for (int i = 0; i < rows - shift; i++) {
// Copy the rows
result[i + shift] = a[i].clone();
}
// Loop it
for (int i = 0; i < shift; i++) {
for (int j = 0; j < cols; j++) {
// Fill with zeros
result[i][j] = 0;
}
}
return result;
}
Я знаю, что поначалу это должно сбивать с толку: такое странное поведение связано с указателями. Изменяя значения строк для вашей функции shift, вы изменили ссылочные типы третьей и четвертой строк на первую и вторую строки.
Проблема в первом цикле. Как следствие, любые изменения, внесенные в первую строку, также отражаются в третьей строке. То же самое касается второго ряда, четвертого. Вы связали их вместе.
Поэтому поменял их и на втором цикле.
Я бы посоветовал вам изменить каждое значение строки вместо ссылочных типов, например:
for (int i = a.length - 1; i >= shift; i--) {
for (int j = 0; j < a[0].length; j++) {
a[i][j] = a[i - shift][j];
}
}
Ваше здоровье!
Спасибо за ваш ответ: «Я бы посоветовал вам изменить каждое значение строки вместо ссылочных типов как таковых:» Я понимаю, что вы имеете в виду, но как мне это сделать? Я понимаю проблему со ссылкой, но как мне сказать Java, чтобы она изменила значение, а не только ссылку?
вы не можете, вы пытаетесь изменить указатель, и вы дали ему новый адрес. Единственное значение, которое может содержать указатель, — это ссылка на другой объект, поэтому ваши единственные возможные варианты — либо создать его клон (другой ответ), либо скопировать материал по значению (мой ответ).
Вот один из способов сделать это. Обратите внимание, что вы можете сделать это, не создавая новый массив для хранения результата. (т. е. вы можете провести смену на месте).
Ключевой момент, на который следует обратить внимание: вы копируете ссылки в массиве. Когда вы сдвигаете массивы слева направо, проблем не возникает. Но вы не можете просто заполнить существующие строки нулями, поскольку вы перезапишете ранее скопированные объекты массива, и они будут изменены.
Кроме того, чем меньше значение сдвига, тем больше требуется копирования. Исключением является значение 0, при котором вы просто возвращаете заданный массив.
int[][] a = {{1,1,1,1,1},{1,1,3,1,1},{1,6,2,1,4},{1,1,1,8,1},
{1,1,1,1,1}};
System.out.println(Arrays.deepToString(move(a, 2)));
принты
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [1, 1, 1, 1, 1], [1, 1, 3, 1, 1], [1, 6, 2, 1, 4]]
выдать исключение, если сдвиг выходит за пределы.
Если массив равен null, empty или значение сдвига равно 0, просто верните исходный массив.
last cell index к shift value, копируя соответствующие ссылки на массив по ходу действия.clone нулевого массива в освободившиеся ячейки, используя shift как index, и уменьшите соответственно.public static int[][] move(int[][] a, int shift) {
// handle special cases
if (shift > a.length || shift < 0) {
throw new IllegalArgumentException(
"Shift value(%d) out of range for array"
.formatted(a.length));
}
if (a == null || a.length == 0 || shift == 0) {
return a;
}
// create zero array replacement
int[] zeros = new int[a[0].length];
Arrays.fill(zeros, 0);
// copy the references
for (int i = a.length-1; i >= shift; i--) {
a[i] = a[i-shift];
}
// fill the "vacated" cells.
while(shift-- > 0) {
a[shift] = zeros.clone();
}
return a;
}
В первом цикле for вы назначаете ссылки на эти строки, а не копируете в них данные. Это означает, что когда вы присваиваете значения, строки смотрят в одни и те же места, поэтому «обе» видят 0.