首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >硬币换币算法

硬币换币算法
EN

Code Review用户
提问于 2016-09-19 22:13:24
回答 1查看 3.3K关注 0票数 6

我用动态规划和贪婪算法w/回溯实现了硬币换币算法。说明如下:

给定一个变化量(n),列出所有可以用来满足变化量的硬币的可能性

如果有一个代码评审来向我展示我在哪里可以提高可读性(还有其他你可能会发现的东西),那就太好了。我一直在努力清理和重构,但是一双新的眼睛会很好。我有点疯狂的评论,因为我想确保我能够在几个月内看到这一点,并没有忘记为什么我做的事情,我这样做。但是也许把一些信息放在一个github维基上会更好。

代码语言:javascript
运行
复制
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

/**
 * Given an amount of change (n) list all of the possibilities of coins that can
 * be used to satisfy the amount of change.
 * 
 * Example: n = 12
 * 
 * 1,1,1,1,1,1,1,1,1,1,1,1
 * 1,1,1,1,1,1,1,5
 * 1,1,5,5
 * 1,1,10
 * 
 * @author Eric
 *
 */
public class CoinChange {
    private int[] coins = { 1, 5, 10, 25 };

    /**
     * Uses a greedy algorithm with backtracking to find the
     * possible combinations
     * 
     * @param sum - the sum of the current combination
     * @param n - the target
     * @param pos - position for which coin to start at
     * @param combination - the current combination
     */
    public void findPossibleCombinations(int sum, int n, int pos, List<Integer> combination) {
        // Begin at pos. We use pos so that we don't have duplicate combinations
        // in different orders ex: 1,1,10 is the same as 1,10,1 or 10,1,1
        // This is possible because when we are at a larger coin, we know that
        // combinations with smaller coins and the larger/current coin
        // have already been found, so we no longer need to consider them.
        // If we did consider them, we would have duplicates.
        // Therefore, pos allows you to only look ahead at larger coins,
        // ignoring smaller coins
        for (int i = pos; i < coins.length; i++) {
            int coin = coins[i];
            sum += coin; // Add the coin to the sum

            // If the sum is larger than n, then we have reached an invalid
            // combination.
            if (sum > n) {
                return;
            }

            combination.add(coin); // Add the coin to the current combination

            // If the sum is equal to n, then we have reached a valid
            // combination. Return from the recursive call
            // because any continuation would be unnecessary as adding more
            // coins or a larger coin would cause the sum to be larger than n.
            if (sum == n) {
                System.out.println(combination);
                combination.remove(combination.size() - 1);
                return;
            }

            findPossibleCombinations(sum, n, pos, combination);

            // Remove the last coin
            combination.remove(combination.size() - 1);
            sum -= coin; // remove the coin from the sum
            pos++;
        }
    }

    /**
     * Uses dynamic programming to find the possible combinations
     * 
     * @param n - the target
     * @return
     */
    public List<List<Integer>> findPossibleCombinationsDP(int n) {
        /**
         * Cell is a class to represent each cell in the n*m grid
         * 
         * @author Eric
         *
         */
        class Cell {
            // All of the possible combinations at each cell
            private List<List<Integer>> combinations = new ArrayList<List<Integer>>();

            List<List<Integer>> getCombinations() {
                return combinations;
            }

            void setCombinations(List<List<Integer>> combinations) {
                this.combinations = combinations;
            }

            void addCombination(List<Integer> combination) {
                if (combination != null) {
                    combinations.add(new ArrayList<Integer>(combination));
                }
            }

        }

        // Create the grid
        Cell[][] sol = new Cell[coins.length + 1][n + 1];

        // Create new cells for the boundary values
        for (int i = 0; i < coins.length + 1; i++) {
            sol[i][0] = new Cell();
        }
        for (int i = 1; i < n + 1; i++) {
            sol[0][i] = new Cell();
        }

        for (int i = 1; i < coins.length + 1; i++) {
            int coin = coins[i - 1];
            for (int j = 1; j < n + 1; j++) {
                Cell cell = new Cell();

                Cell prevCoinCell = sol[i - 1][j];
                // Copy the combinations
                cell.setCombinations(prevCoinCell.getCombinations());

                if (j == coin) {
                    // Only need to add the coin as a combination by itself in this case
                    cell.addCombination(new ArrayList<Integer>(Arrays.asList(coin)));
                } else if (coin < j) {
                    // In this case we need to get the previous cell minus the
                    // size of the coin. Each combination needs to have
                    // the current combination added to it
                    Cell prevCell = sol[i][j - coin];
                    for (List<Integer> prevCombination : prevCell.getCombinations()) {
                        List<Integer> combination = new ArrayList<Integer>(prevCombination);
                        combination.add(coin);
                        cell.addCombination(combination);
                    }
                }
                sol[i][j] = cell;
            }
        }
        return sol[coins.length][n].getCombinations();
    }

    public static void main(String[] args) {
        CoinChange cc = new CoinChange();
        int n = 21;
        List<List<Integer>> combinations = cc.findPossibleCombinationsDP(n);
        System.out.println("Possible Combinations using Dynamic Programming");
        for(List<Integer> combination : combinations){
            System.out.println(combination);
        }
        System.out.println("\nPossible Combinations using Greedy Algorithm with Backtracking");
        cc.findPossibleCombinations(0, n, 0, new ArrayList<Integer>());
    }

}
EN

回答 1

Code Review用户

发布于 2017-03-24 10:19:05

6个月后,在codereview上仍然没有答案可能是一个好迹象。这意味着没有人会发现你的代码有什么大问题,也不会为那些琐碎的事情烦恼。

也许得到这个答案可能是一个很好的时间来检查您自己的代码,看看现在您自己会做什么不同的事情。

我唯一能说的是这段代码的“错误”是您选择变量名,然后添加大量注释的原因。

你的大部分评论实际上都很合适。更具体地说,那些解释你为什么要做某事的人。特别是从小到大订购硬币的重要性。

有些评论是这样的:

代码语言:javascript
运行
复制
combination.add(coin); // Add the coin to the current combination

如果您选择更好的变量名(虽然组合也没有那么糟糕),这是有点没用的。

所以我唯一真正的改变就是

代码语言:javascript
运行
复制
public void findPossibleCombinations(
        int sum, int n, int pos, List<Integer> combination) {

代码语言:javascript
运行
复制
public void findPossibleCombinations(
        int currentTotal, 
        int targetAmmount, 
        int currentCoinIndex, 
        List<Integer> currentChange) {

或者更好的名字如果你能找到他们。希望你的一些评论是多余的。

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/141853

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档