我用动态规划和贪婪算法w/回溯实现了硬币换币算法。说明如下:
给定一个变化量(n),列出所有可以用来满足变化量的硬币的可能性
如果有一个代码评审来向我展示我在哪里可以提高可读性(还有其他你可能会发现的东西),那就太好了。我一直在努力清理和重构,但是一双新的眼睛会很好。我有点疯狂的评论,因为我想确保我能够在几个月内看到这一点,并没有忘记为什么我做的事情,我这样做。但是也许把一些信息放在一个github维基上会更好。
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>());
}
}发布于 2017-03-24 10:19:05
6个月后,在codereview上仍然没有答案可能是一个好迹象。这意味着没有人会发现你的代码有什么大问题,也不会为那些琐碎的事情烦恼。
也许得到这个答案可能是一个很好的时间来检查您自己的代码,看看现在您自己会做什么不同的事情。
我唯一能说的是这段代码的“错误”是您选择变量名,然后添加大量注释的原因。
你的大部分评论实际上都很合适。更具体地说,那些解释你为什么要做某事的人。特别是从小到大订购硬币的重要性。
有些评论是这样的:
combination.add(coin); // Add the coin to the current combination如果您选择更好的变量名(虽然组合也没有那么糟糕),这是有点没用的。
所以我唯一真正的改变就是
public void findPossibleCombinations(
int sum, int n, int pos, List<Integer> combination) {至
public void findPossibleCombinations(
int currentTotal,
int targetAmmount,
int currentCoinIndex,
List<Integer> currentChange) {或者更好的名字如果你能找到他们。希望你的一些评论是多余的。
https://codereview.stackexchange.com/questions/141853
复制相似问题