Вы можете уменьшить количество необходимых циклов, предполагая, что установленное число
- имеет только положительные значения
- Сумма набора больше, чем значение, которое нужно вычесть
- Это может быть отсортировано.
По пункту 3. Вы сказали в комментариях, что это хорошо, так что вот алгоритм, который я имею в виду.Это многословно с точки зрения имен переменных, но, надеюсь, это проясняет ситуацию.В общем, это не слишком сложно:
const result = subtractFromSet([4, 5, 6, 7, 8], 25);
console.log(result)
function subtractFromSet(numberSet, totalToSubtract) {
return numberSet.map((currentMember, index, wholeSet) => {
const remainingElements = wholeSet.length - index
const averageToSubtract = totalToSubtract / remainingElements;
const toSubtract = Math.min(averageToSubtract, currentMember);
//modify both the total remaining to subtract and the current element
totalToSubtract -= toSubtract;
return currentMember - toSubtract;
})
}
Чтобы объяснить это словами, вот что происходит
- Вычитание значения из суммы набора аналогично вычитаниюзначение делится на размер набора от каждого члена.Таким образом,
[4, 5, 6, 7, 8] - 25
будет 4 - 5
, 5 - 5
, 6 - 5
и т. Д. - Если мы не хотим отрицаний, то мы только вычитаем до текущего члена.Таким образом, с текущим членом
4
и средним значением 25 / 5 = 5
мы можем только вычесть 4
. - . Чтобы распределить остаток, мы просто добавляем его обратно к общей сумме, чтобы вычесть оставшуюся часть.членов.Поэтому, когда мы доберемся до второго члена
5
, среднее значение теперь равно (25 - 4) / (5 - 1)
, потому что мы не могли вычесть полное 5
среднее значение в первый раз, только 4
, а оставшиеся элементы на один меньше.Это дает 5.25
.
И поэтому, проходя через каждого члена и корректируя общее значение, а затем среднее значение, необходимое для вычитания, мы получаем правильный результат.Однако следует помнить о арифметике с плавающей точкой в программировании, так как это может привести к незначительным результатам.Если вы соберете достаточно значимые цифры для своих нужд, вы можете этого избежать.
И последнее: как я уже сказал, входные данные должны быть отсортированы.Это можно легко сделать так:
const unsortedArray = [6, 4, 7, 8, 5];
const sortedArray = unsortedArray.sort((a, b) => a - b)
console.log(sortedArray);
Я упустил из вышеприведенного алгоритма, чтобы сосредоточиться на том, что мы на самом деле делаем с отсортированным вводом.
Общая сложность этого алгоритма довольно приличная- Приличная сортировка принесет вам O(n log(n))
сложность времени.Зависит от реализации сортировки и набора данных - 5 элементов, вероятно, будут отсортированы с помощью O(n^2)
Bubblesort, но опять же, это 5 элементов, поэтому, вероятно, это не окажет никакого влияния.Запуск алгоритма вычитания прост O(n)
.Сложность пространства для вычитания составляет O(2n)
, потому что .map()
делает копию массива.Я выбрал это, поскольку это немного чище, потому что у вас все еще есть вход.Но вы также можете выполнять вычитание на месте с минимальными изменениями, и это даст вам O(n)
сложность пространства.
const input = [4, 5, 6, 7, 8];
subtractFromSet(input, 25);
console.log(input);
function subtractFromSet(numberSet, totalToSubtract) {
numberSet.forEach((currentMember, index, wholeSet) => { //using .forEach instead of .map
const remainingElements = wholeSet.length - index
const averageToSubtract = totalToSubtract / remainingElements;
const toSubtract = Math.min(averageToSubtract, currentMember);
//modify both the total remaining to subtract and the current element
totalToSubtract -= toSubtract;
wholeSet[index] = currentMember - toSubtract; //modify the array directly
})
}