E outra coisa, não precisa do while
para ficar subtraindo uma nota de cada vez. Vc pode ver quantas notas precisa, e subtrair tudo de uma vez:
function cashWithdrawal(value, availableNotes) {
let notes = [];
let availableNotesOriginal = structuredClone(availableNotes);
// array com os valores de todas as notas disponíveis
const allNotesValues = Object.keys(availableNotes).map((note) => Number(note)).sort((a, b) => b - a);
for (const subsetNotes of subsets(allNotesValues, 0, 2)) {
let remainingValue = value;
for (const noteValue of subsetNotes) {
// quantas notas desse valor eu preciso?
const need = Math.min(Math.floor(remainingValue / noteValue), availableNotes[noteValue]);
for (let i = 0; i < need; i++) { // adiciona as notas
notes.push(noteValue);
}
// subtrai a quantidade e atualiza o valor restante
availableNotes[noteValue] -= need;
remainingValue -= noteValue * need;
}
if (remainingValue == 0) { // se o valor zerou, é porque deu certo
const availableNotesSum = Object.entries(availableNotes).reduce((sum, [note, quantity]) => sum + Number(note) * quantity, 0);
return {
notes,
availableNotes,
availableNotesSum
};
} else {
// se não deu certo, zera o array de notas e volta para as notas disponíveis original
notes = [];
availableNotes = JSON.parse(JSON.stringify(availableNotesOriginal));
}
// se o valor não zerou, é porque não foi possível, então tenta com a próxima combinação de notas
}
return null; // se tentou todas as combinações e chegou aqui, é porque não é possível
}
Ou seja, basta dividir o valor restante pelo valor da nota para saber quantas eu preciso. Mas se não tiver notas suficientes, eu pego tudo que tem disponível e continuo com a próxima nota.
E faço isso até acabar as notas, e vejo se o valor restante é zero, para saber se deu certo.