简体   繁体   中英

Recursive Method in a Coins Method

For this question I have to write a method where when the user puts in a money amount in pennies I have to output all the possible combinations with dimes, nickels, and pennies in a String format. I can only use recursion and no type of loops or collections(ie arrays, lists, stacks, etc). This code should work but for some reason it doesnt output all the combinations, its missing the: "0d 3n 7p" & "0d 0n 17p" outputs.

package Assignement02;

public class Coins {

    public static String ways (int money) {

        System.out.println("Enter an amount in cents:");
        System.out.println(money);
        System.out.println("This amount can be changed in the following ways:");

        if(money == 0) {

            return "there are no ways to change that amount";

        } else {

            return waysHelper(0, 0, 0, money);
        }


    }

    public static String waysHelper(int countd, int countn, int countp, int money) {


        if(money >= 10) {

            countd++;
            return waysHelper(countd, countn, countp, money - 10);

        } else if (money >= 5) {

            countn++;
            return waysHelper(countd, countn, countp, money - 5);

        } else {


                String s = " " + countd + "d, " + countn + "n, " + money + "p";
                int orig = 10*countd + 5*countn + money;
               return counterHelper(orig, countd, countn, money, s);


            }
        }

    public static String counterHelper(int money, int countd, int countn, int countp, String s) {

        if(countp == money) {

            s = s + s + "\n " + countd + "d, " + countn + "n, " + countp + "p";
        }

        if(countd > 0) {

            if(countn > 0) {

                countn--;
                countp = countp + 5;
                s = s + "\n " + countd + "d, " + countn + "n, " + countp + "p";
                counterHelper(money, countd, countn, countp, s);
            }

            countd--;
            countn = countn + 2;
            s = s + "\n " + countd + "d, " + countn + "n, " + countp + "p";
            counterHelper(money, countd, countn, countp, s);

        } 

        if(countn > 0) {

            countn--;
            countp = countp + 5;
            s = s + "\n " + countd + "d, " + countn + "n, " + countp + "p";
            counterHelper(money, countd, countn, countp, s);

        }

        if(countn > 0) {

            countn--;
            countp = countp + 5;
            s = s + "\n " + countd + "d, " + countn + "n, " + countp + "p";
            counterHelper(money, countd, countn, countp, s);

        }

        return s;
    }



    public static void main(String[] args) {

        System.out.print(ways(17));


    }
}

Output:

Enter an amount in cents: 17 This amount can be changed in the following ways: 1d, 1n, 2p 1d, 0n, 7p 0d, 2n, 7p 0d, 1n, 12p 0d, 0n, 17p

Your problem would be more obvious if you had used 37 cents as your test case. You never have any example with more than two nickels, because you divert to dimes first and never come back. You only make up for that with the extra if (countn...) steps, in a way I don't quite follow.

Rather than have the waysHelper return a String, you should pass in a List of Strings (or just have one as a member variable) and each call to waysHelper will add some to the List. If you haven't done Lists yet, you can build this up in a big String, but you have to be careful because then you have to return it, capture each modified version, and always pass that along. With a List, you pass it in and the method you are calling can modify it.

The whole idea of doing this recursively rather than using a loop is a little silly, but note that tail recursion and loops are essentially the same thing. You can take advantage of this.

import java.util.ArrayList;
import java.util.List;

public class MoneyChangers {
    public static void main(String[] args) {
        List<String> results = new ArrayList<>();
        getCombos(results, 28, 0);
        System.out.println(results);
    }

    public static void getCombos(List<String> results, int target, int dimesCount) {
        int pennies = target - 10 * dimesCount;
        if (pennies < 0) {
            return;
        }
        getCombosForDimesFixed(results, target, dimesCount, 0);

        // This is tail recursion, which is really just a loop.  Do it again with one more dime.
        getCombos(results, target, dimesCount+1);
    }

    private static void getCombosForDimesFixed(List<String> results, int target, int dimesCount, int nickelsCount) {
        int pennies = target - 10 * dimesCount - 5 * nickelsCount;
        if (pennies < 0) {
            return;
        }
        results.add("\n" + dimesCount + "d, " + nickelsCount + "n, " + pennies + "p");
        getCombosForDimesFixed(results, target, dimesCount, nickelsCount+1);   // tail recursion again
    }
}

I believe you have generally the correct idea on the problem breakdown. This is how I see your interpretation:

  1. Convert the starting pennies into the largest denomination combination of coins possible (ie for 17 it would be 1d, 1n, 2p)
  2. Break down that "largest denomination combination" into every combination of smaller coins to determine all the possible combinations (ie break each dime down into 2 nickels, and each nickel down into 5 pennies)

With your waysHelper being the first part and your counterHelper being the second part.

Find my solution below with comments inline:

public class Coins {

    public static void main(String[] args) {
        System.out.print(findAllCoinCombinationsForPennies(17));
    }

    public static String findAllCoinCombinationsForPennies(int money) {
        System.out.println("Enter an amount in cents:");
        System.out.println(money);
        System.out.println("This amount can be changed in the following ways:");
        if(money <= 0) {
            return "there are no ways to change that amount";
        } else {
            return findAllCoinCombinations(0, 0, money);
        }
    }

    // break down the initial amount into the largest coinage to start (i.e. 17 pennies will be 1d, 1n, 2p)
    private static String findAllCoinCombinations(int dimes, int nickels, int pennies) {
        if(pennies >= 10) {
            // we can still convert pennies to another dime
            return findAllCoinCombinations(dimes + 1, nickels, pennies - 10);
        } else if (pennies >= 5) {
            // we can still convert pennies to another nickel
            return findAllCoinCombinations(dimes, nickels + 1, pennies - 5);
        } else {
            // base case where we have the largest coins (can't convert pennies to any more dimes or nickels)
            return findCoinCombinationsFor(dimes, nickels, pennies, "");
        }
    }

    // find all combinations of coins recursively
    private static String findCoinCombinationsFor(int dimes, int nickels, int pennies, String output) {
        // each call is another combination of coins, add that combination to our result output
        output += "\n " + dimes + "d, " + nickels + "n, " + pennies + "p";
        if (dimes > 0) {
            // if we have dimes, break the dime down into 2 nickels
            return findCoinCombinationsFor( dimes - 1, nickels + 2, pennies, output);
        } else if (nickels > 0) {
            // if we have nickels break each nickel down into 5 pennies
            return findCoinCombinationsFor( dimes, nickels - 1, pennies + 5, output);
        } else {
            // we have no more dimes or nickels, return the accumulated output
            return output;
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM