Нечётные числа должны отсортироваться по возрастанию, а чётные должны остаться на своих местах
Дан массив:
const nums = [1,9,4,2,3,6,7,1,5];
Необходимо написать функцию sortOddNums, которая принимает аргументом массив чисел и возвращает массив чисел, в котором нечётные числа отсортированы по возрастанию, а чётные оставлены на своих местах:
sortOddNums(nums) // [1,1,4,2,3,6,5,7,9];
Примеры:
[1,9,4,2,3,6,7,1,5] --> [1,1,4,2,3,6,5,7,9]
[1,4,3,7,9,5,2,1,6] --> [1,4,1,3,5,7,2,9,6]
[5,3,6,234,67,63,212,24,11] --> [3,5,6,234,11,63,212,24,67]
[1,2,3,4,5,6,7,8,9] --> [1,2,3,4,5,6,7,8,9]
[10,356,11,258,2,978,3,15,4] --> [10,356,3,258,2,978,11,15,4]
Теория по задаче
Задача относится к классу «частичная сортировка с фиксацией позиций»: сортируются только элементы, удовлетворяющие условию (нечётные), а остальные (чётные) сохраняют исходные индексы. Решение удобно строить как «разделение → сортировка → сборка результата», потому что обычная сортировка всего массива нарушит требование «чётные остаются на своих местах».
Как определить чётность и нечётность
В JavaScript чаще всего применяется оператор остатка %:
- Чётное число:
n % 2 === 0. - Нечётное число:
n % 2 !== 0.
% в JavaScript является оператором остатка, а не математического модуля: результат сохраняет знак делимого. Например, -3 % 2 даёт -1, и условие нечётности n % 2 !== 0 по-прежнему корректно определяет нечётные числа (остаток не равен нулю).3.5), то понятия «чётное/нечётное» теряют смысл. Для учебной задачи предполагаются целые числа.Почему нельзя «просто отсортировать»
У Array.prototype.sort() есть две особенности, которые важны:
- Без компаратора элементы сортируются как строки (лексикографически), что может дать неправильный порядок для чисел (например,
100может оказаться «меньше»2при строковом сравнении). sort()изменяет массив «на месте», то есть мутация может привести к тому, что исходные данные будут потеряны.
Отсюда следует правило: для сортировки чисел необходимо передавать компаратор (a, b) => a - b, а при необходимости сохранять исходный массив — сортировать копию.
Пример корректной числовой сортировки (демонстрационный):
const arr = [9, 1, 10, 2];
arr.sort((a, b) => a - b); // [1, 2, 9, 10]
Базовый алгоритм «разделение → сортировка → сборка»
Алгоритм удобно описывать так:
- Выделение: из исходного массива выбираются все нечётные элементы (например, через
filterили циклом). - Сортировка: полученный список нечётных сортируется по возрастанию числовым компаратором.
- Сборка: создаётся новый массив-результат, в котором:
- на позициях с чётными числами остаются исходные значения;
- на позициях с нечётными числами последовательно подставляются элементы из отсортированного списка.
Схема потока данных (на примере):
исходный nums: [1, 9, 4, 2, 3, 6, 7, 1, 5]
нечётные odds: [1, 9, 3, 7, 1, 5]
отсорт. odds: [1, 1, 3, 5, 7, 9]
результат: [1, 1, 4, 2, 3, 6, 5, 7, 9]
Ключевая идея: чётные значения вообще не перемещаются, изменяются только значения в тех индексах, где изначально стояли нечётные числа.
Почему `map()` удобно для сборки
map() проходит массив по индексам слева направо и создаёт новый массив той же длины. Это позволяет на каждом шаге принимать решение: если текущий элемент нечётный, то подставляется следующее значение из отсортированного списка нечётных, иначе возвращается исходное чётное значение.
Механика указателя i:
iхранит «номер следующего нечётного числа» в отсортированном массивеodds.- Каждый раз при встрече нечётного элемента в исходном массиве берётся
odds[i], после чегоiувеличивается на 1.
Фрагмент (демонстрационный):
let i = 0;
const result = nums.map((n) => (n % 2 !== 0 ? odds[i++] : n));
Сложность (время и память)
Пусть n — длина массива, k — количество нечётных элементов:
- Время: выделение нечётных — O(n), сортировка нечётных — O(k log k), сборка результата — O(n). Итог: O(n + k log k).
- Память: список нечётных — O(k), новый массив результата — O(n) (если требуется вернуть новый массив).
k заметно меньше n), сортировка выполняется быстрее, чем сортировка всего массива длины n, потому что сортируется только подмножество.Частые ошибки и как их избегать
- Ошибка: сортировка без компаратора
sort()для чисел; исправление: обязательно задавать(a, b) => a - b. - Ошибка: вызов
sort()на массиве, который нельзя менять; исправление: сортировать копию (slice(),[...arr]) или применятьtoSorted(). - Ошибка: подмена нечётных чисел без сохранения порядка обхода; исправление: подставлять нечётные строго по порядку индексов слева направо (подходит
map()или цикл по исходному массиву). - Ошибка: попытка «переставлять элементы местами» в исходном массиве; исправление: не перемещать чётные вообще, а только заменять значения в нечётных позициях.
Кратко: в задаче необходимо сортировать только нечётные элементы, сохраняя чётные на исходных индексах, поэтому решение строится как: сбор нечётных → числовая сортировка (a, b) => a - b → последовательная подстановка обратно в нечётные позиции. Важно помнить, что sort() мутирует массив, поэтому при сохранении исходных данных требуется сортировать копию или использовать toSorted().