#java #arrays #for-loop #exception
Вопрос:
Я сделал этот код для поворота массива в k раз. В этом случае , когда я добавляю i=0, он показывает исключение «ArrayOutOfBounds», а когда я изменяю значение i на 1, он показывает неправильный вывод. Почему он показывает это исключение? И есть ли какой-нибудь способ исправить этот код?
public void rotate(int[] nums, int k)
{ int j=0, temp=0;
for(j=0;j<k;j )
{
for(int i=0;i<nums.length;i )
{
temp=nums[i-1];
nums[i-1]=nums[i];
nums[i]=temp;
}
}
}
}
Комментарии:
1. Ибо
i=0
,nums[i-1]
становитсяnums[-1]
.2. Если i равно 0, вы пытаетесь получить индекс -1, который вызовет
ArrayOutOfBounds
исключение. Если я начну с 1, то вы имеете дело не с первым номером.3. @DavidLee, Есть ли что-нибудь, что я могу изменить, чтобы избежать этой ошибки и получить правильный вывод в этой программе?
4. Зачем вам нужно повторять k раз для каждой замены? вы можете выполнить k-сдвиг напрямую, и алгоритм станет O(n) вместо O(n*k).
Ответ №1:
Правка (из комментариев выше): Если i равен 0, вы пытаетесь получить индекс -1, который вызовет исключение ArrayOutOfBounds. Если я начну с 1, то вы имеете дело не с первым номером.
Вот функция, которую вы можете использовать для поворота целых чисел вправо:
public void rotate(int[] nums, int k) {
int arrLen = nums.length;
// If the number of times you want to rotate is bigger than the size of the array, get the minimum number of rotations to get the same result.
while (k > n) {
k = k - arrLen;
}
k = arrLen - k;
k = k % arrLen;
int i, m, n, temp;
int g_c_d = gcd(k, arrLen);
// Move the value in the i-th index
for (i = 0; i < g_c_d; i ) {
temp = arr[i];
m = i;
while (true) {
n = m k;
if (n >= arrLen) {
n = n - arrLen;
}
if (n == i) {
break;
}
arr[m] = arr[n];
m = n;
}
arr[m] = temp;
}
}
// Find the greatest common divisor of two numbers, a and b
public void gcd(int a, int b) {
if (b == 0) {
return a;
} else {
return gcd(b, a % b);
}
}
Позвольте мне вкратце объяснить, что он делает. Это один из самых известных алгоритмов: жонглирование. Вы делите массив на n наборов, где n обозначает наибольший общий делитель длины массива и количество раз, которое вы хотите повернуть. Затем вы перемещаете числа внутри наборов.
Это может быть наиболее эффективным с точки зрения времени (поскольку его временная сложность составляет O(n)).
Комментарии:
1. Да, другой показывал превышение срока, этот работает лучше.
Ответ №2:
На i=0
вы пытаетесь получить доступ nums[i-1]
= num[-1]
, что является недопустимой позицией, и, следовательно, возникает ArrayOutOfBound
исключение.
Таким образом, измененная версия будет:
for (j=0; j<k; j )
{
for (int i=1;i<nums.length;i )
{
temp=nums[i-1];
nums[i-1]=nums[i];
nums[i]=temp;
}
}
Но вышеизложенное повернет массив в k
разы вправо left
, когда вы перемещаете элементы влево. Итак, чтобы получить right
вращение, вам нужно переместить элементы с конца массива. Нравится:
for (j=0; j<k; j )
{
for (int i=nums.length-1; 0<i; i--)
{
// shifting towards the right
temp=nums[i-1];
nums[i-1]=nums[i];
nums[i]=temp;
}
}
Ответ №3:
Лучшим решением было бы сделать копию данного массива со значениями «0», а затем пройтись по данному массиву, чтобы получить new_index.
Формула для New_index для тактовой вращающейся матрицы:
for(int i=0;i<nums.length;i ){
int new_index = (old_index k)%(a.length)
copy[new_index] = a[old_index]
}
Now the entire function code would be:
public static void rotate(int[] a, int k)
{
int n = a.length;
int[] copy = new int[n];
// fill the values with zeroes
for(int i=0;i<n;i ){
copy[i]=0;
}
// rotate the array
for(int i=0;i<n;i ){
int new_index = (i k)%n;
copy[new_index] = a[i];
}
// Now that the array is copied, copy the elements to the original array. Because they asked to rotate the given array.
for(int i=0;i<n;i ){
a[i]=copy[i];
}
}