Демипиксель
ЗАМЕТКА: Если вы работаете через бесплатный код Code и не завершили эту проблему, я действительно рекомендую попробовать это сначала!
Я возился с бесплатным кодом лагеря и был оспоренен кем-то, чтобы попытаться правильно выполнить проблему «точных изменений».
Эта проблема
Точная проблема изменения просит вас написать функцию, которая выводит наименьшее количество монет, чтобы добавить до заданного количества денег, и данный 2D массив монет отформатировал что-то вроде:
[["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.10], ["QUARTER", 4.25], ["ONE", 90.00], ["FIVE", 55.00], ["TEN", 20.00], ["TWENTY", 60.00], ["ONE HUNDRED", 100.00]]
Обратите внимание, как он показывает, что у нас есть 1,01 доллар на пенни, а не с указанием «101 копейки».
Неправильное решение
Так что бесплатный кодовый лагерь для начинающих, поэтому я могу понять, что ответ, который они предоставляют, будут наиболее интуитивными для людей, пытающихся понять, как это работает. К сожалению, алгоритм не всегда имеет желаемый эффект. Вы можете увидеть полный фрагмент кода здесь , но это краткое описание того, что он делает:
coinList = []
for each denomination while amountLeft < coinValue && coinLeft > 0 Add the coin to coinList coinLeft-- amountLeft -= coinValue
if (coinList.length == 0 || amountLeft > 0) return "Insufficient Funds"otherwise return the array
И хотя это может показаться простым и блестящим решением, мы столкнулись с некоторыми проблемами. Мне было опрошено конкретно для следующего теста:
0,30 доллара с десятью и кварталами
Допустим, мы хотим получить 0,30 доллара в 10 центов и 10 кварталов (поэтому у нас более чем достаточно центов или кварталов). Это где предыдущий алгоритм немного поезжает.
Способ, который он использует, состоит в том, чтобы использовать наивысшую деноминацию и идти вниз до достижения цели или самого низкого значения. Сначала он пытается использовать четверть (поскольку это самая высокая доступная деноминация) и остается на 0,05 доллара.
Поскольку сумма (сумма денег, оставленных на монетах), это> 0, он возвращает «недостаточно средств», потому что ценя более чем 0,05 доллара, и не осталось других конденсаций. Тем не менее, мы все знаем, что правильное решение состоит в том, чтобы заработать 0,30 доллара с тремя десятками!
Мы не можем начать с самого низкого наименования и работать (например, начать в десять центов, а затем перейти к кварталам), потому что мы могли бы столкнуться с проблемой, как 0,40 доллара с 1 никелем, 3 центами и 1 квартал.
Программа начнет, пытаясь использовать никель ($ 0,05, самым низким значением), затем 3 центов ($ 0,35, вторая обозначение в использовании) и вернется «недостаточно средств», потому что мы не можем сделать наши оставшиеся $ 0,05 с десятью или кварталами Отказ Это не пыталось 1 никель, 1 десять центов и 1 квартал (что точно составляет $ 0,40).
Меньшие проблемы
Давайте начнем просто. Как мы могли бы сделать проблему, если бы мы хотели, чтобы монеты зарабатывали $ 0,01? Ну, мы проходим к конфетациям и проверь, чтобы убедиться, что у нас достаточно этой монеты (то есть достаточно копейки), а чем монета стоит <= 0,01 доллара (какая пенни).
Теперь давайте посмотрим на 0,02 доллара. Для людей легко увидеть, что $ 0,02 – это просто два копейки от $ 0,00.
Однако для компьютера это не так просто. То, что мы можем сделать для компьютера, – это выразить достижение $ 0,02 как «1 пенни более $ 0,01». Мы также можем выразить 0,03 доллара в качестве копейки более 0,02 доллара.
Больший пример будет на 1,00 доллара. $ 1,00 – пенни + $ 0,99 или никель + $ 0,95 или дэйма + $ 0,90 или квартал + $ 0,75 или долларовой балл + $ 0,00. Поскольку пять долларовых законопроектов превышает 1,00 доллара, мы просто игнорируем его (и любые более высокие обозначения).
Поэтому, если мы вернемся к нашей оригинальной проблеме и хотите рассчитать 0,30 доллара от центов и кварталов, нам сначала нужно рассчитать и сохранить комбинацию монет, чтобы заработать 0,01 доллара. Затем рассчитайте и сохраните за 0,02 доллара. Затем за 0,03 доллара за 0,03 доллара 0,04, $ 0,05 и так далее, пока мы доберемся до 0,30 доллара.
Каждый раз, когда мы хотим следующее значение (например, 0,20 $), мы смотрим на значение 0,20 $ и вычесть тип монет, мы находимся в петле деноминации (например, ценя).
Это оставляет нас с 0,20 доллара минус центов, что составляет 0,10 доллара, и мы можем просто сказать «добавить падежи + монеты, которые составляют 0,10 доллара». Это, вероятно, будет представлено как массив монет, поэтому представьте, что 0,10 доллара – это [«десять центов». Поскольку мы говорим, что «копейки + монеты, которые составляют 0,10 доллара», уделяют 0,20 доллара «, мы можем сказать, что $ 0,20 – это [« десять центов », потому что мы добавляем дополнительную монету (десять центов) в наш список.
Идеально! 0,20 доллара – два цента.
Лучшее соотношение
Если мы вернемся к нам $ 1,00, у нас много способов достижения того же значения. Как мы знаем, что лучше? Как мы узнаем, лучше ли использовать долларовую купюру или лучше использовать DIME + $ 0,90 в монетах? Мы могли бы сказать «самая большая деноминация – лучшая». Поскольку один доллар законопроект – наше наибольшее количество полезных деноминаций, мы бы просто укажем, что один доллар Билл является лучшим выбором (и установить $ 1,00 до [«1 доллар»]).
Так что же $ 0,30 дано 5 копейки, 3 центов и 1 квартал? Используя метод «Крупнейший номинал», мы бы попытаемся сделать 0,30 доллара от «DIME + $ 0,20» или «квартала + $ 0,05». Похоже, что квартал – лучший вариант (квартал + $ 0,05), когда на самом деле, что дает нам шесть монетных ответов (четверть и пять копейки), когда мы хотим трех монетных ответов (три десятка)!
Что мы действительно хочем, это сравнить количество монет. Поскольку меньше монет в 0,20 доллара (два цента), чем в 0,05 доллара (пять копейки), ценя за 0,30 доллара + является оптимальным выбором за 0,30 доллара.
На практике
Поскольку мы просто нахожу лучший со значением за 0,01 доллара, затем 0,02 доллара, затем $ 0,03, так что включено и так далее, мы можем просто использовать для петли вместо рекурсии или в то время как цикл!
Теперь, на самом деле было бы невозможно сохранить значения как [«десять центов», «десять центов», «квартал», как я заявил выше. То, как я хранил, это было с массивом целых чисел, в формате [пенни, никели, десять центов, четверти и т. Д.]. Таким образом, 3 квартала и 2 центов будут [0, 0, 2, 3, 0, 0, 0, 0] (составляют до 20 долларов, поскольку это максимальная деноминация в проблеме).
В моем коде я называю количество монет «оценка». Если вы не знакомы с ним, o (_), это формат, который позволяет программистам показывать, насколько эффективна определенная программа, и насколько хорошо она будет работать при расширении.
Сейчас я хотел, чтобы алгоритм быть о (деньгами * деноминациями), однако, необходимость пересчитывать счет каждый раз, когда сделает его (деньги * деноминацию ^ 2). То, что я решил сделать, было просто создать другую переменную для хранения балла, как я храня лучшие суммы. Итак, если я хотел 0,30 доллара от десятина + $ 0,20, я мог бы посмотреть на BestScorleList [0,20 долл. США] и увидеть, что он дал значение «2».
Поскольку нить одна монета, мы просто делаем BestScorList [0,20] + 1, что составляет 3. Если это смущает вас, не волнуйтесь. Просто помните, что BestScoreList [i] (ex value: 5) собирается сохранить количество монет в лучшем виде [i] (ex value: [2, 0, 3, 0, 0, 0, 0, 0]) без определения всегда пересчитать его.
Наконец, в нашей проблеме на 0,30 доллара мы добираемся до 0,20 доллара + десять центов или 0,05 доллара за квартал. С $ 0,05 – 0 монет (поскольку нет никакого способа получить $ 0,05 от кварталов и центов), он утверждает, что 1 квартал является лучшим решением.
Лучший способ противодействовать этому, чтобы просто испортить счет, если счет 0, и он не доступа к 0,00 доллара. Например, $ 0.10 с целом может вернуть счет «1», потому что $ 0,00 имеет оценку 0, и поэтому он добавляет 1. Однако, если у нас есть 0,15 долл. США только с десятью ценями, он вернет счет «0», потому что 0,05 доллара составляет 0,05 доллара (не зарабатывает 0,05 доллара за 90 долларов!) И $ 0,05 – не 0,00 (очевидно).
Мы разрушаем счет, потому что это означает, что это невозможное решение (поскольку мы хотим достичь $ 0,00, и это невозможно с этим конкретным деноминацией).
Код
Вот код и тестовый случай 0,30 доллара с проблемами центов и кварталов. Он использует немного ES6, поэтому измените, что если вы не можете использовать это по какой-то причине. Также обратите внимание, что проблема дала «наличными» (наличными) и «цена предмета» в цене. Это означает, что мы на самом деле хотим дать им монеты наличными. Вот!
Оригинал: “https://www.freecodecamp.org/news/exact-solution-for-exact-change-81e1d23bfe58/”