Задать вопрос
@badman4235

Как переставить элементы массива из конца в начало?

Есть функция которая принимает массив и число n. Функция должна переставить n элементов массива из конца в начало.
Пример:
console.log(
  moveToStart ([1, 2, 3, 4, 5], 3)
); // [3, 4, 5, 1, 2]
  • Вопрос задан
  • 1691 просмотр
Подписаться 1 Простой 1 комментарий
Решения вопроса 4
@Asokr
function moveToStart(array, n) {
    return [...array.slice(-n),...array.slice(0, array.length - n)]
}
Ответ написан
Комментировать
function moveToStart(arr, n) {

	if(n && n < arr.length) {

		while(n--)
			arr.unshift(arr.pop());
	}

	return arr;
}

console.log(moveToStart([1, 2, 3, 4, 5], 3)); // [3, 4, 5, 1, 2]


UPD: в этой версии, вместо итераций, применяется метод slice

function moveToStart(arr, n) {

	const amount = arr.length - n;

	return arr.slice(amount).concat(arr.slice(0, amount));
}

console.log(moveToStart([1, 2, 3, 4, 5], 3)); // [3, 4, 5, 1, 2]
Ответ написан
const moveToStart = (arr, n) => [ ...arr.splice(-n), ...arr ];
Ответ написан
Комментировать
wataru
@wataru
Разработчик на С++, экс-олимпиадник.
Большинство решений, уже предложенных тут, работают за квадрат и уже для n=10000 amount=5000 будут работать заметно долго. Конечно, вряд ли такое большое количество данных будет на клиенте, но даже при n=100, если функция выполняется часто, зачем ее делать в ~50 раз медленнее?

Решение, предложенное Павел - самое лучшее. Работает быстро и, как и многие алгоритмически правильные решения, оно гораздо короче и читабельнее остальных решений.

Если хотите без splice(), то надо завести новый массив и потом скопировать в него элементы n-amount..n-1 в начало одним циклом, потом вторым циклом скопировать дальше элементы 0..n-amount-1.

Зафиксированный вами интерфейс предполагает использование нового массива для результатов каждый раз. Но можно было бы сделать без использования много дополнительной памяти, тусуя сам массив на месте, если допустить изменение интерфейса.

Правда, splice уже нельзя было бы использовать. Еще надо было бы знать теорию перестановок немного. Короче, вот решение, которое работает за линию и перемешивает массив на месте:

function gcd(a,b) {
 if (a>b) return gcd(b,a);
 return a == 0? b : gcd(b%a, a);
}

function next(i, k) {
  return i >= k ? i-k : i+n-k
}

function moveToStartInPlace(arr, k) {
  n = arr.length;
  num_cycles = gcd(k,n)
  for (i=0; i < num_cycles; ++i) {
   saved_value = arr[i];
   j = i;
   nxt = next(j, k);
   while (nxt != i) { 
     arr[j] = arr[nxt];
     j = nxt;
     nxt = next(j, k);
   }
   arr[j] = saved_value;
  }
}


Возможно, это не лучшая реализация - я не специалист по JS. Суть этого решения в том, что мы берем какой-то элемент и ставим на его место нужный элемент после перестановки. На освободившееся место ставим следующий элемент и так далее, пока не вернемся к начальной позиции (а мы всегда вернемся, потому что перестановки только так и работают).

Функция next() возвращает, какой элемент должен встать на место i-ого в итоговом массиве.
Если немного подумать, то станет понятно, что в перестановке ровно gcd(n,k) циклов, потому что в ней все прыжки делаются на +(n-k) или -k. Т,е. фактически делаются только прыжки -k(mod n). А это уже известный факт: если прыгать по массиву на +k, оборачиваясь из конца в начало, то мы вернемся в ту же точку, с которой начали и всего таких циклов будет gcd(n,k).
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы
23 дек. 2024, в 09:41
5000 руб./за проект
23 дек. 2024, в 09:39
1000000 руб./за проект