Прежде всего, я предлагаю использовать точные имена переменных.Это позволит всем, в том числе и вам самим, понять, как работает алгоритм.Ваш текущий массив "coins" - это не список монет, это список доступных купюр, поэтому он должен называться "denominations" или "denominations_available" или что-то в этом роде.Переменная, которую вы называете «сумма», представляет собой оставшуюся сумму, поэтому она должна называться либо «оставшаяся», либо сумма_ремонтная.список, который обрабатывается как стек. Например, вы можете использовать ArrayList of Integers. Каждый раз, когда вы вызываете coinChange, добавляйте номинал выбранной монеты (denominations [idx]) в свой список, прежде чем делать вызов. Каждый раз, когда вывернуть -1 (ошибка), удалить последний элемент в списке (если он есть) перед возвратом. Когда условие успеха будет достигнуто (amount_remaining == 0), список монет будет содержать используемые монеты.
Исправление: так как coinChange вызывается несколько раз в цикле, стек должен выталкиваться после каждого вызова, а лучший минимум отбрасывается назад после его определения, поэтому он должен идти следующим образом:
int best_coin = 0;
for (int x = 0; x <= maxVal; x++) {
if (amount >= x * coins[idx]) {
<<<<<< PUSH GOES HERE
int res = coinChange(idx + 1, coins, amount - x * coins[idx]);
<<<<<< POP GOES HERE
if (res == -1){
// failed to find valid combination of coins
} else {
if( minCost < res + x ){
// do nothing
} else { // update minimum
minCost = res + x;
best_coin = coins[idx];
}
}
}
<<<<<< PUSH BEST COIN
return (minCost == Integer.MAX_VALUE) ? -1 : minCost;