Encontrei um código que estava escrevendo para a preparação da entrevista alguns meses atrás.
De acordo com o comentário que fiz, estava tentando resolver este problema:
Dado algum valor em dólares em centavos (por exemplo, 200 = 2 dólares, 1000 = 10 dólares), encontre todas as combinações de moedas que compõem o valor em dólares. São permitidos apenas centavos (1 ¢), nickels (5 ¢), moedas (10 ¢) e quartos (25 ¢).
Por exemplo, se 100 foi fornecido, a resposta deve ser:
4 quarter(s) 0 dime(s) 0 nickel(s) 0 pennies
3 quarter(s) 1 dime(s) 0 nickel(s) 15 pennies
etc.
Eu acredito que isso pode ser resolvido de forma iterativa e recursiva. Minha solução recursiva tem muitos bugs, e eu queria saber como outras pessoas resolveriam esse problema. A parte difícil desse problema era torná-lo o mais eficiente possível.
algorithm
recursion
puzzle
coin-change
codingbear
fonte
fonte
code-golf
=> stackoverflow.com/questions/tagged/code-golfRespostas:
Eu pesquisei isso uma vez, há muito tempo, e você pode ler meu pequeno artigo sobre isso . Aqui está a fonte do Mathematica .
Usando funções geradoras, você pode obter uma solução de tempo constante de forma fechada para o problema. Graham, Knuth e Patashnik's Concrete Mathematics é o livro para isso, e contém uma discussão bastante extensa do problema. Essencialmente, você define um polinômio onde o n- ésimo coeficiente é o número de maneiras de fazer alterações por n dólares.
As páginas 4-5 do artigo mostram como você pode usar o Mathematica (ou qualquer outro sistema de álgebra computacional conveniente) para calcular a resposta de 10 ^ 10 ^ 6 dólares em alguns segundos em três linhas de código.
(E isso foi há muito tempo que são alguns segundos em um Pentium 75 MHz ...)
fonte
a
como o domínio def
masa = {1,5,10,25,50,100}
. Deve haver um 5 na lista de moedas de centavo. Fora isso, o artigo foi fantástico, obrigado!Nota : Isso mostra apenas o número de maneiras.
Função Scala:
fonte
n1 * coins(0) + n2 * coins(1) + ... + nN * coins(N-1) = money
. Portanto, paramoney=0
ecoins=List(1,2,5,10)
a contagem para combinações(n1, n2, n3, n4)
é 1 e a solução é(0, 0, 0, 0)
.money == 0
mascoins.isEmpty
, não deveria contar como um sol'n. Portanto, o algoritmo pode ser melhor atendido se acoins.isEmpty || money < 0
condição for examinada primeiro.Eu seria a favor de uma solução recursiva. Você tem alguma lista de denominações, se a menor delas puder dividir igualmente qualquer valor de moeda restante, isso deve funcionar bem.
Basicamente, você passa das denominações maiores para as menores.
Recursivamente,
Aqui está minha versão python do seu problema declarado, por 200 centavos. Eu recebo 1463 maneiras. Esta versão imprime todas as combinações e o total da contagem final.
fonte
denominations
não tiver1
como último valor. Você pode adicionar uma pequena quantidade de código aoif
bloco mais interno para corrigi-lo (conforme descrevo em minha resposta à outra pergunta).Função Scala:
fonte
Aqui estão alguns códigos C ++ absolutamente diretos para resolver o problema que exigia que todas as combinações fossem mostradas.
Mas estou bastante intrigado com o problema secundário de apenas calcular o número de combinações. Suspeito que haja uma equação de forma fechada para isso.
fonte
O subproblema é um problema típico de Programação Dinâmica.
fonte
O código está usando Java para resolver esse problema e também funciona ... Esse método pode não ser uma boa ideia por causa de muitos loops, mas é realmente uma maneira direta.
fonte
Esta é uma questão muito antiga, mas eu vim com uma solução recursiva em java que parecia menor do que todas as outras, então aqui vai -
Melhorias:
fonte
Seja C (i, J) o conjunto de combinações de fazer i centavos usando os valores do conjunto J.
Você pode definir C assim:
(primeiro (J) assume de forma determinística um elemento de um conjunto)
Acontece uma função bastante recursiva ... e razoavelmente eficiente se você usar memoização;)
fonte
semi-hack para contornar o problema de combinação única - forçar ordem decrescente:
Isso ficará lento, pois não será memorizado, mas essa é a ideia.
fonte
fonte
Esta é minha resposta em Python. Não usa recursão:
Saída de exemplo
fonte
fonte
Ambos: itera através de todas as denominações de alto a baixo, pegue um de denominação, subtraia do total solicitado e, em seguida, repasse no restante (restringindo denominações disponíveis para serem iguais ou menores ao valor de iteração atual).
fonte
Se o sistema monetário permitir, um algoritmo simples e ganancioso que pega o máximo possível de cada moeda, começando com a moeda de maior valor.
Caso contrário, a programação dinâmica é necessária para encontrar uma solução ótima rapidamente, uma vez que este problema é essencialmente o problema da mochila .
Por exemplo, se um sistema monetário tem as moedas
{13, 8, 1}
:, a solução gananciosa faria a troca por 24 as{13, 8, 1, 1, 1}
, mas a verdadeira solução ótima é{8, 8, 8}
Edit: Achei que estávamos fazendo a mudança de forma otimizada, não listando todas as maneiras de fazer a mudança por um dólar. Minha entrevista recente perguntou como fazer a mudança, então pulei em frente antes de terminar de ler a pergunta.
fonte
Eu sei que esta é uma questão muito antiga. Eu estava procurando a resposta correta e não consegui encontrar nada que fosse simples e satisfatório. Levei algum tempo, mas fui capaz de anotar algo.
Esta é uma solução javascript e usa recursão.
fonte
Na linguagem de programação Scala, eu faria assim:
fonte
Este é um algoritmo recursivo simples que pega uma nota e, em seguida, pega uma nota menor recursivamente até atingir a soma, então pega outra nota da mesma denominação e recorre novamente. Veja o exemplo de saída abaixo para ilustração.
Imprime o seguinte:
fonte
Duh, me sinto estúpido agora. Abaixo, há uma solução excessivamente complicada, que preservarei porque , afinal, é uma solução. Uma solução simples seria esta:
Aqui está a outra solução. Esta solução baseia-se na observação de que cada moeda é um múltiplo das outras, para que possam ser representadas em termos delas.
Então, para 37 moedas, por exemplo:
fonte
Esta entrada do meu blog resolve esse problema tipo mochila para as figuras de uma história em quadrinhos do XKCD . Uma simples mudança no
items
dict e noexactcost
valor resultará em todas as soluções para o seu problema também.Se o problema fosse encontrar a mudança que usava o menor custo, então um algoritmo ingênuo e ganancioso que usava tanto da moeda de maior valor poderia falhar para algumas combinações de moedas e valor alvo. Por exemplo, se houver moedas com os valores 1, 3 e 4; e a quantidade desejada é 6, então o algoritmo ganancioso pode sugerir três moedas de valor 4, 1 e 1 quando for fácil ver que você pode usar duas moedas de valor 3 cada.
fonte
fonte
Eu encontrei esse código legal no livro "Python For Data Analysis", de O'reily. Ele usa implementação preguiçosa e comparação interna e presumo que possa ser modificado para outras denominações usando decimais. Deixe-me saber como funciona para você!
fonte
Essa é a melhora da resposta de Zihan. A grande quantidade de loops desnecessários ocorre quando a denominação é de apenas 1 centavo.
É intuitivo e não recursivo.
fonte
Solução java simples:
fonte
fonte
Aqui está uma função C #:
Use-o assim:
Ele imprime:
fonte
Abaixo está um programa python para encontrar todas as combinações de dinheiro. Esta é uma solução de programação dinâmica com tempo de ordem (n). O dinheiro é 1,5,10,25
Atravessamos a moeda 1 para a moeda 25 (4 linhas). O dinheiro da linha 1 contém a contagem se considerarmos apenas o dinheiro 1 no cálculo do número de combinações. O dinheiro da linha 5 produz cada coluna pegando a contagem do dinheiro da linha r para o mesmo dinheiro final mais a contagem das 5 anteriores em sua própria linha (posição atual menos 5). Dinheiro de linha 10 usa dinheiro de linha 5, que contém contagens de 1,5 e soma na contagem de 10 anteriores (posição atual menos 10). Dinheiro de linha 25 usa dinheiro de linha 10, que contém contagens para dinheiro de linha 1,5,10 mais a contagem de 25 anteriores.
Por exemplo, números [1] [12] = números [0] [12] + números [1] [7] (7 = 12-5) que resulta em 3 = 1 + 2; números [3] [12] = números [2] [12] + números [3] [9] (-13 = 12-25) que resulta em 4 = 0 + 4, já que -13 é menor que 0.
fonte
Solução Java
}
fonte
A solução Java abaixo que também imprimirá as diferentes combinações. Fácil de entender. Ideia é
para soma 5
A solução é
Se a soma restante em cada loop for menor do que a denominação, ou seja, se a soma restante 1 for menor que 2, basta interromper o loop
O código completo abaixo
Por favor, me corrija em caso de algum erro
}
fonte
Aqui está uma solução baseada em Python que usa recursão, bem como memoização, resultando em uma complexidade de O (mxn)
fonte