【问题标题】:Recursive Method in a Coins Method硬币方法中的递归方法
【发布时间】:2020-02-12 21:57:19
【问题描述】:

对于这个问题,我必须编写一个方法,当用户以便士输入金额时,我必须以字符串格式输出所有可能的硬币、镍和便士组合。我只能使用递归,不能使用任何类型的循环或集合(即数组、列表、堆栈等)。这段代码应该可以工作,但由于某种原因它没有输出所有组合,它缺少:“0d 3n 7p”和“0d 0n 17p”输出。

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));


    }
}

输出:

输入以美分为单位的金额: 17 可以通过以下方式更改此金额: 1d、1n、2p 1d、0n、7p 0d、2n、7p 0d、1n、12p 0d、0n、17p

【问题讨论】:

    标签: java recursion methods recursive-query


    【解决方案1】:

    如果您使用 37 美分作为测试用例,您的问题会更加明显。你永远不会有超过两个镍币的例子,因为你先转向一角钱,然后再也不回来了。您只能通过额外的 if (countn...) 步骤来弥补这一点,这在某种程度上我并不完全遵循。

    而不是让waysHelper 返回一个字符串,您应该传入一个字符串列表(或者只将一个字符串作为成员变量),并且每次调用waysHelper 都会将一些字符串添加到列表中。如果您还没有完成 Lists,您可以在一个大字符串中构建它,但您必须小心,因为您必须返回它,捕获每个修改后的版本,并始终传递它。使用 List,您将其传入,您调用的方法可以对其进行修改。

    递归而不是使用循环的整个想法有点愚蠢,但请注意尾递归和循环本质上是一回事。您可以利用这一点。

    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
        }
    }
    

    【讨论】:

    • 我认为他将结果附加到字符串的原因是因为他的问题定义:“我只能使用递归,而不能使用任何类型的循环或集合(即数组、列表、堆栈等) "
    • 非常感谢您的帮助,我将重新配置我的代码,以便我可以利用尾递归。不幸的是,我们不能使用任何类型的集合,因此,我将传递并修改一个大字符串。
    • 另一种选择是在找到它们时打印它们。也就是说,我现在将它们放入列表中,而不是 System.out.println 那个结果。
    【解决方案2】:

    我相信您对问题分解的总体思路是正确的。这就是我对您的解释的看法:

    1. 将起始便士转换为可能的最大面额硬币组合(例如,对于 17,它将是 1d、1n、2p)
    2. 将“最大面额组合”分解为较小硬币的每个组合,以确定所有可能的组合(即,将每个硬币分成 2 个镍币,每个镍币分成 5 个便士)

    你的waysHelper是第一部分,你的counterHelper是第二部分。

    使用 cmets 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;
            }
        }
    }
    

    【讨论】:

    • 你说得对,我设法改正了这个错误。感谢您的意见和帮助
    猜你喜欢
    • 2023-03-02
    • 1970-01-01
    • 1970-01-01
    • 2020-04-11
    • 1970-01-01
    • 2012-09-19
    • 2018-10-07
    • 2015-07-20
    • 1970-01-01
    相关资源
    最近更新 更多