I am stuck on the coin denomination problem.
I am trying to find the lowest number of coins used to make up $5.70 (or 570 cents). For example, if the coin array is {100,5,2,5,1} (100 x 10c coins, 5 x 20c, 2 x 50c, 5 x $1, and 1 x $2 coin), then the result should be {0,1,1,3,1}
At the moment the coin array will consist of the same denominations ( $2, $1, 50c, 20c, 10c)
public static int[] makeChange(int change, int[] coins) {
// while you have coins of that denomination left and the total
// remaining amount exceeds that denomination, take a coin of that
// denomination (i.e add it to your result array, subtract it from the
// number of available coins, and update the total remainder). –
for(int i= 0; i< coins.length; i++){
while (coins[i] > 0) {
if (coins[i] > 0 & change - 200 >= 0) {
coins[4] = coins[4]--;
change = change - 200;
} else
if (coins[i] > 0 & change - 100 >= 0) {
coins[3] = coins[3]--;
change = change - 100;
} else
if (coins[i] > 0 & change - 50 >= 0) {
coins[2] = coins[2]--;
change = change - 50;
} else
if (coins[i] > 0 & change - 20 >= 0) {
coins[1] = coins[1]--;
change = change - 20;
} else
if (coins[i] > 0 & change - 10 >= 0) {
coins[0] = coins[0]--;
change = change - 10;
}
}
}
return coins;
}
I am stuck on how to deduct the values from coins array and return it.
EDIT: New code
The brute force solution is to try up to the available number of coins of the highest denomination (stopping when you run out or the amount would become negative) and for each of these recurse on solving the remaining amount with a shorter list that excludes that denomination, and pick the minimum of these. If the base case is 1c the problem can always be solved, and the base case is return n otherwise it is n/d0 (d0 representing the lowest denomination), but care must be taken to return a large value when not evenly divisible so the optimization can pick a different branch. Memoization is possible, and parameterized by the remaining amount and the next denomination to try. So the memo table size would be is O(n*d), where n is the starting amount and d is the number of denominations.
So the problem can be solved in pseudo-polynomial time.
The wikipedia link is sparse on details on how to decide if a greedy algorithm such as yours will work. A better reference is linked in this CS StackExchange question. Essentially, if the coin system is canonical, a greedy algorithm will provide an optimal solution. So, is [1, 2, 5, 10, 20] canonical? (using 10s of cents for units, so that the sequence starts in 1)
According to this article, a 5-coin system is non-canonical if and only if it satisfies exactly one of the following conditions:
[1, c2, c3] is non-canonical (false for [1, 2, 5])
it cannot be written as [1, 2, c3, c3+1, 2*c3] (true for [1, 2, 5, 10, 20])
the greedyAnswerSize((k+1) * c4) > k+1 with k*c4 < c5 < (k+1) * c4; in this case, this would require a k*10 < 20 < (k+1)*10; there is no integer k in that range, so this is false for [1, 2, 5, 10, 20].
Therefore, since the greedy algorithm will not provide optimal answers (and even if it did, I doubt that it would work with limited coins), you should try dynamic programming or some enlightened backtracking:
import java.util.HashSet;
import java.util.PriorityQueue;
public class Main {
public static class Answer implements Comparable<Answer> {
public static final int coins[] = {1, 2, 5, 10, 20};
private int availableCoins[] = new int[coins.length];
private int totalAvailable;
private int totalRemaining;
private int coinsUsed;
public Answer(int availableCoins[], int totalRemaining) {
for (int i=0; i<coins.length; i++) {
this.availableCoins[i] = availableCoins[i];
totalAvailable += coins[i] * availableCoins[i];
}
this.totalRemaining = totalRemaining;
}
public boolean hasCoin(int coinIndex) {
return availableCoins[coinIndex] > 0;
}
public boolean isPossibleBest(Answer oldBest) {
boolean r = totalRemaining >= 0
&& totalAvailable >= totalRemaining
&& (oldBest == null || oldBest.coinsUsed > coinsUsed);
return r;
}
public boolean isAnswer() {
return totalRemaining == 0;
}
public Answer useCoin(int coinIndex) {
Answer a = new Answer(availableCoins, totalRemaining - coins[coinIndex]);
a.availableCoins[coinIndex]--;
a.totalAvailable = totalAvailable - coins[coinIndex];
a.coinsUsed = coinsUsed+1;
return a;
}
public int getCoinsUsed() {
return coinsUsed;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder("{");
for (int c : availableCoins) sb.append(c + ",");
sb.setCharAt(sb.length()-1, '}');
return sb.toString();
}
// try to be greedy first
#Override
public int compareTo(Answer a) {
int r = totalRemaining - a.totalRemaining;
return (r==0) ? coinsUsed - a.coinsUsed : r;
}
}
// returns an minimal set of coins to solve
public static int makeChange(int change, int[] availableCoins) {
PriorityQueue<Answer> queue = new PriorityQueue<Answer>();
queue.add(new Answer(availableCoins, change));
HashSet<String> known = new HashSet<String>();
Answer best = null;
int expansions = 0;
while ( ! queue.isEmpty()) {
Answer current = queue.remove();
expansions ++;
String s = current.toString();
if (current.isPossibleBest(best) && ! known.contains(s)) {
known.add(s);
if (current.isAnswer()) {
best = current;
} else {
for (int i=0; i<Answer.coins.length; i++) {
if (current.hasCoin(i)) {
queue.add(current.useCoin(i));
}
}
}
}
}
// debug
System.out.println("After " + expansions + " expansions");
return (best != null) ? best.getCoinsUsed() : -1;
}
public static void main(String[] args) {
for (int i=0; i<100; i++) {
System.out.println("Solving for " + i + ":"
+ makeChange(i, new int[]{100,5,2,5,1}));
}
}
}
You are in wrong direction. This program will not give you an optimal solution. To get optimal solution go with dynamic algorithms implemented and discussed here. Please visit these few links:
link 1
link 2
link 3
Related
There's a question I saw and I'm wondering if it's possible to solve it using recursion. It goes as follow:
Write an algorithm that, when given an array of input, finds the maximum product from those inputs. For example:
Input: [1, 2, 3]
Output: 6 (1*2*3)
Input: [-1, 1, 2, 3]
Output: 6 (1*2*3)
Input: [-2, -1, 1, 2, 3]
Output: 12 (-2*-1*1*2*3)
I'm trying to find a way of using recursion to solve it, but the algorithm I tried doesn't work. My algorithm, written in Java is as follow
Integer[] array;
public int maximumProduct(int[] nums) {
array=new Integer[nums.length];
return multiply(nums, 0);
}
public int multiply(int[] nums, int i){
if (array[i]!=null){
return array[i];
}
if (i==(nums.length-1)){
return nums[i];
}
int returnval=Math.max(nums[i]*multiply(nums, i+1), multiply(nums, i+1));
array[i]=returnval;
return returnval;
}
The problem with this algorithm is that it doesn't work well if there's an even number of negative numbers. For example, if nums[0]=-2, nums[1]=-1 and nums[2]=1, then multiply(nums, 1) will always return 1 instead of -1, and thus it will always see 1 as bigger than 1*-2 at multiply(nums, 0). I'm not sure how to solve this problem, however. Is there any way of solving this using recursion or dynamic programming?
If there is only one non-zero element in the array, and it happens to be a negative number, then then answer is either 0, if there is a 0 present in the input, or if the array contains only that single negative element, the answer is that element itself.
In all other cases, the final answer is going to be positive.
We first make a linear scan to find the number of negative integers. If this number is even, then the answer is the product of all the non-zero elements. If there are an odd number of negative elements, we need to leave out one negative element from the answer, so that the answer is positive. As we want the maximum possible answer, the number we want to leave out should have as small an absolute value as possible. So among all the negative numbers, find the one with the minimum absolute value, and find the product of the remaining non-zero elements, which should be the answer.
All this requires only two linear scans of the array, and hence runs in O(n) time.
What is the maximum product of integers?
To obtain the maximum sum, you will want to multiply all the positive integers with the product of the largest negative integers, with the number of negative integers included in the product being even to obtain a positive final result.
In an algorithm for a single traversal
I am going to treat the positive integers and the negative integers in the input separately. You will want to keep a running product of positive integers, a running product of negative integers and the largest negative integer (ie. the negative integer with the smallest absolute value) found so far.
Let us ignore the edge cases where the final answer is <= 0. That can be handled easily.
//Initialization
int [] nums // Input
int posProduct = 1;
int negProduct = 1;
int smallestNeg = 1;
//Input Traversal
for (int i : nums) {
if ( i == 0 ) {
// ignore
} else if ( i < 0 ) {
if (smallestNeg == 1) {
smallestNeg = i;
} else if ( i > smallestNeg ) {
negProduct *= smallestNeg; //Integrate the old smallest into the running product
smallestNeg = i; // i is the new smallest
} else {
negProduct *= i;
}
} else {
// i is strictly positive
posProduct *= i;
}
}
//Result Computation
int result = posProduct;
if ( negProduct < 0 ) {
// The running product of negative number numbers is negative
// We use the smallestNeg to turn it back up to a positive product
result *= smallestNeg;
result *= negProduct;
} else {
result *= negProduct
}
edit: In a recursive traversal
I personally find that writing the array traversal in a recursive manner to be clumsy but it can be done.
For the beauty of the exercise and to actually answer the question of the OP, here is how I would do it.
public class RecursiveSolver {
public static int findMaxProduct (int [] nums) {
return recursiveArrayTraversal(1, 1, 1, nums, 0);
}
private static int recursiveArrayTraversal(int posProduct, int negProduct,
int smallestNeg, int [] nums, int index) {
if (index == nums.length) {
// End of the recursion, we traversed the whole array
posProduct *= negProduct;
if (posProduct < 0) {
posProduct *= smallestNeg;
}
return posProduct;
}
// Processing the "index" element of the array
int i = nums[index];
if ( i == 0 ) {
// ignore
} else if ( i < 0 ) {
if (smallestNeg == 1) {
smallestNeg = i;
} else if ( i > smallestNeg ) {
negProduct *= smallestNeg;
smallestNeg = i;
} else {
negProduct *= i;
}
} else {
// i is strictly positive
posProduct *= i;
}
//Recursive call here!
//Notice the index+1 for the index parameter which carries the progress
//in the array traversal
return recursiveArrayTraversal(posProduct, negProduct,
smallestNeg, nums, index+1);
}
}
First, break the array in subproblems always you find a 0 in the list:
1 -2 4 -1 8 0 4 1 0 -3 -4 0 1 3 -5
|_____________| |____| |____| |_______|
p1 p2 p3 p4
Then, for each problem pi, count how many negative numbers are there.
If pi has an even number of negatives (or no negatives at all), the answer of pi is the product of all its elements.
If pi has only 1 negative number (say n), the answer will be the maximum between the product of all the elements in n's right and the product of all elements in n's left.
If pi has an odd number (bigger than only 1) of negative numbers, call the index of the leftmost negative number l and the index of the rightmost negative number r. Supposing pi has n elements, the answer will be:
max(
pi[ 0 ] * pi[ 1 ] * ... * pi[r - 1],
pi[l + 1] * pi[l + 2] * ... * pi[ n ]
)
Knowing that, it's easy to write a recursion for each step of the solution of this problem: a recursion to divide problems at zeros, another to count negatives and another to find answers, in O(n).
Linear version
List<Integer> vals = new ArrayList<>(List.of(5,1,-2,1,2,3,-4,-1));
int prod = 0;
int min = 1;
for (int v : vals) {
if (v == 0) {
// ignore zero values
continue;
}
if (prod == 0) {
prod = 1;
}
prod *= v;
// compute min to be the largest negative value in the list.
if (v < 0 && min < Math.abs(v)) {
min = v;
}
}
if (prod < 0) {
prod /= min;
}
System.out.println("Maximum product = " + prod);
}
Recursive version
int prod = prod(vals, new int[] {0} , vals.size());
System.out.println("Maximum product = " + prod);
public static int prod(List<Integer> vals, int[]min, int size) {
int prod = 0;
if(vals.size() > 0) {
int t = vals.get(0);
if (t < 0 && min[0] < Math.abs(t)) {
min[0] = t;
}
prod = prod(vals.subList(1,vals.size()), min, vals.size());
}
if (vals.isEmpty() || vals.get(0) == 0) {
return prod;
}
if (prod == 0) {
prod = 1;
}
prod *= t;
if (vals.size() == size && prod < 0) {
prod/=min[0];
}
return prod;
}
This is my solution - leaving it open for optimization and to figure out the runtime. This is a general purpose solution that finds the products of all the combinations of integers in a list. Of course, there is a O(n) solution but I present this solution as well.
import java.util.ArrayList;
import java.util.List;
public class MaxProd {
int[] input = {1, 2, 3};
// int[] input = {-2, -1, 1, 2, 3};
public static void main(String[] args) {
MaxProd m = new MaxProd();
List<Integer> ll = m.max(0);
for (int i : ll) {
System.out.println(i);
}
ll.sort((x,y) -> Integer.compare(x, y));
System.out.println("The max: " + ll.get(ll.size() -1 ));
}
private List<Integer> max(int index) {
if (index < input.length){
List<Integer> l = new ArrayList<>();
List<Integer> retList = max(index + 1);
for (int j : retList){
l.add(input[index] * j);
}
l.add(input[index]);
l.addAll(retList);
return l;
}
else return new ArrayList<>();
}
}
it prints:
6
2
3
1
6
2
3
The max: 6
If the requirements are constrained (as in this case) then one can get by without the need for generating all combinations resulting in a linear solution. Also, I'm sorting at the end. Note: you could easily get the result with a single pass on the returned list to find the maximum product as specified in other answers.
I wrote a simple program to calculate the maximum number of times square root can be calculated on a number , input is an interval from num1 to num2
eg:
if the input is (1,20), answer is 2, since square root of 16 is 4 , and square root of 4 is 2 .
int max = 0;
for (int i = num1; i <= num2; i++) {
boolean loop = true;
int count = 0;
int current = i;
if (i == 1) {
count++;
} else {
while (loop) {
double squareRoot = Math.sqrt(current);
if (isCurrentNumberPerfectSquare(squareRoot)) {
count++;
current = (int) squareRoot;
} else {
loop = false;
}
}
}
if (count > max) {
max = count;
}
}
return max;
static boolean isCurrentNumberPerfectSquare(double number) {
return ((number - floor(number)) == 0);
}
I get the answer, but was wondering wether this can be improved using some mathematical way ?
Any suggestions ?
To avoid more confusion here my final answer to this topic.
A combination of both previously mentioned approaches.
What 'Parameswar' is looking for is the largest perfect square formed by the lowest base.
Step 1 -
To get that calculate the largest possible perfect square based on your num2 value.
If it is outside your range, you have no perfect square within.
Step 2 -
If it is within your range, you have to check all perfect square formed by a lower base value with a higher number of times.
Step 3 -
If you find one that is within your range, replace your result with the new result and proceed to check lower values. (go back to Step 2)
Step 4 -
Once the value you check is <= 2 you have already found the answer.
Here some sample implementation:
static class Result {
int base;
int times;
}
static boolean isCurrentNumberPerfectSquare(double number) {
return ((number - Math.floor(number)) == 0);
}
private static int perfectSquare(int base, int times) {
int value = base;
for (int i = times; i > 0; i--) {
value = (int) Math.pow(base, 2);
}
return value;
}
private static Result calculatePerfectSquare(int perfectSquare) {
Result result = new Result();
result.base = (int) Math.sqrt(perfectSquare);
result.times = 1;
while (result.base > 2 && isCurrentNumberPerfectSquare(Math.sqrt(result.base))) {
result.base = (int) Math.sqrt(result.base);
result.times += 1;
}
System.out.println(perfectSquare + " -> " + result.base + " ^ " + result.times);
return result;
}
static int maxPerfectSquares(int num1, int num2) {
int largestPerfectSqr = (int) Math.pow(Math.floor(Math.sqrt(num2)), 2);
if (largestPerfectSqr < num1) {
return 0;
}
Result result = calculatePerfectSquare(largestPerfectSqr);
int currentValue = result.base;
while (currentValue > 2) {
// check lower based values
currentValue--;
int newValue = perfectSquare(currentValue, result.times + 1);
if (newValue >= num1 && newValue < num2) {
result = calculatePerfectSquare(newValue);
currentValue = result.base;
}
}
return result.times;
}
Edit - My assumption is incorrect. Refer to the answer provided by "second".
You can remove the outer loop, num2 can be directly used to determine the number with the maximum number of recursive square roots.
requiredNumber = square(floor(sqrt(num2)));
You just need to check to see if the requiredNumber exists in the range [num1, num2] after finding it.
So the refactoring code would look something like this,
int requiredNumber = Math.pow(floor(Math.sqrt(num2)),2);
int numberOfTimes=0;
if(requiredNumber>=num1) {
if (requiredNumber == 1) {
numberOfTimes=1;
} else{
while (isCurrentNumberPerfectSquare(requiredNumber)) {
numberOfTimes++;
}
}
}
Edit 4: for a more optimal approach check my other answer.
I just leave this here if anybody wants to try to follow my thought process ;)
Edit 3:
Using prime numbers is wrong, use lowest non perfect square instead
Example [35,37]
Edit 2:
Now that I think about it there is a even better approach, especially if you assume that num1 and num2 cover a larger range.
Start with the lowest prime number 'non perfect square' and
calculate the maximum perfect square that fits into your range.
If you have found one, you are done.
If not continue with the next prime number 'non perfect square'.
As a example that works well enough for smaller ranges:
I think you can improve the outerloop. There is no need to test every number.
If you know the smallest perfect square, you can just proceed to the next perfect square in the sequence.
For example:
[16, 26]
16 -> 4 -> 2 ==> 2 perfect squares
No neeed to test 17 to 24
25 -> 5 ==> 1 perfect square
and so on ...
#Chrisvin Jem
Your assumption is not correct, see example above
Edit:
Added some code
static int countPerfectSquares(int current) {
int count = 0;
while (true) {
double squareRoot = Math.sqrt(current);
if (isCurrentNumberPerfectSquare(squareRoot)) {
count++;
current = (int) squareRoot;
} else {
return count;
}
}
}
static boolean isCurrentNumberPerfectSquare(double number) {
return ((number - Math.floor(number)) == 0);
}
static int numPerfectSquares(int num1, int num2) {
int max = 0;
if (num1 == 1) {
max = 1;
}
int sqr = Math.max(2, (int) Math.floor(Math.sqrt(num1)));
int current = (int) Math.pow(sqr, 2);
if (current < num1) {
current = (int) Math.pow(++sqr, 2);
}
while (current <= num2) {
max = Math.max(countPerfectSquares(current), max);
current = (int) Math.pow(++sqr, 2);
}
return max;
}
I have a brute force solution with backtracking to solve the coin change problem. Currently i get minimum number of coins that can be used. But how could i also return the coins that were actually used? So for example if the amount is 100 then i would like to return [25, 25, 25, 25].
My current code is below:
public class Solution {
public static void main(String[] args) {
Solution s = new Solution();
int coinChange = s.coinChange(0, new int[] { 1, 25, 50 }, 100);
System.out.println(coinChange);
}
public int coinChange(int idx, int[] coins, int amount) {
if (amount == 0){
return 0;
}
if (idx < coins.length && amount > 0) {
int maxVal = amount / coins[idx];
int minCost = Integer.MAX_VALUE;
for (int x = 0; x <= maxVal; x++) {
if (amount >= x * coins[idx]) {
int res = coinChange(idx + 1, coins, amount - x * coins[idx]);
if (res != -1)
minCost = Math.min(minCost, res + x);
}
}
return (minCost == Integer.MAX_VALUE) ? -1 : minCost;
}
return -1;
}
}
First of all, I suggest using accurate variable names. That will make it a lot easier for everyone, yourself included, to understand how the algorithm works. Your current array "coins" is not a list of coins, it is a list of available denominations, so it should named "denominations" or "denominations_available" or something like that. The variable you call "amount" is the amount remaining, so it should be named either "remaining" or amount_remaining".
To store the list of coins used so far, you can use a stack, or just a list that is treated like a stack. For example, you could use an ArrayList of Integers. Every time you call coinChange, add the denomination of the chosen coin (denominations[idx]) to your list before you make the call. Every time you return -1 (failure), remove the last item on the list (if there is one) before you return. When the success condition is reached (amount_remaining==0), the coin list will contain the coins used.
Correction: since coinChange is called multiple times in a loop, the stack must be popped after every call and the best minimum is pushed back again after it is determined. So, it should go like this:
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;
So I am not very good at it yet at all (understatement). I am trying to solve problems in the Euler project, and I am already stuck on 2.
Each new term in the Fibonacci sequence is generated by adding the previous 2 terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
Here is my code which I have repeatedly tried to fix:
(I think there is something wrong with the for loop logic.)
public class tesy {
public static void main(String args[]) {
int fib = 0;
int tot = 0;
int total = 0;
for (fib = 0; tot < 4000000; fib++) {
tot = fib + (fib + 1);
if (tot % 2 == 0) {
total = tot + total;
}
}
System.out.println(total);
}
}
Your logic is erroneous in couple of ways,
tot = fib + (fib + 1); /** This will always be `(2*fib + 1)` and `fib` is getting
incremented by 1 each time. You have no reference to the previous two terms of the
sequence. **/
Try the below logic instead.
class Fibonacci
{
public static void main (String[] args)
{
int fiboFirst = 1;
int fiboSecond =2;
int fib = 0;
int sum = 0;
while(fiboSecond < 4000000)
{
// This will calculate the current term of the sequence
fib = fiboFirst + fiboSecond;
// Below two lines will update fib[i] and fib[i - 1] terms
// for the next loop iteration.
fiboFirst = fiboSecond; // fib[i]
fiboSecond = fib; // fib[i -1]
if (fib % 2 == 0)
{
sum = sum + fib;
}
}
System.out.println(sum+2);
}
}
Explanation
Here fiboFirst is equivalent to F[n] and fiboSecond is equivalent
to F[n - 1] in the Fibonacci sequence definition. In each iteration,
those two values should be replaced, in order to be used in the next
iteration. That is why I have these two lines,
fiboFirst = fiboSecond; // fib[i]
fiboSecond = fib; // fib[i -1]
HERE is the execution of the above program
You don't seem to be following the actual equation used to generate a fibonacci sequence, therefore there is no (obvious) way of fixing your code.
int fibA = 1, fibB = 2, total = 0;
while(fibB <= 4000000) {
// Add to the total, set fibA to fibB and get the next value in the sequence.
if(fibB % 2 == 0) total += fibB;
int temp = fibA;
fibA = fibB;
fibB = fibB + temp;
}
The above code should find the sum of all values less than or equal to 4000000
Here is a solution that uses BigInteger. Please verify the results.
public class Fibonacci{
public static void main(String[] args) {
BigInteger r = fibonacciEvenSum();
System.out.println(r);
}
public static BigInteger fibonacciEvenSum(){
int f = 1;
int s = 2;
int mn4 = 4000000;
BigInteger sum = BigInteger.valueOf(0);
while(s <= mn4){
if(s % 2 == 0){
sum = sum.add(BigInteger.valueOf(s));
}
f = f + s;
s = s + f;
}
return sum;
}
}
Before writing a program like this, you should first think of what's underlying this program. You should first understand how to generate a Fibonacci series before graduating on to doing something with the series. I'll give you my solution so that you can understand.
class euler2 {
public static void main(String[] args) {
int a = 0, b = 1; /* the first elements of Fibonacci series are generally
thought to be 0 and 1. Therefore the series is 0, 1, 1, 2, 3... .
I've initialized first and second elements such */
double sum = 0; // The initial sum is zero of course.
while (b < 4000000) /* since b is the second term, it will be our control variable.
This wouldn't let us consider values above 4M. */
{
int ob = b; // to swap the values of a and b.
b = a + b; // generating next in the series.
a = ob; // a is now the older value of b since b is now a + b.
if (b % 2 == 0) // if b is even
sum += b; // we add it to the sum
}
System.out.println(sum); // and now we just print the sum
}
}
Hope this helped!
So I wrote a recursive algorithm for the problem of figuring out the least number of 'coins' of a particular set of denominations possible to arrive at a given sum. The algorithm seems to work, but because it's recursive, and calculates every possible option before choosing one or the other, I'm having a difficult time coming up with a way to print out the denominations used as well. So essentially I can calculate the least number of coins possible to use, but not which coins they are. Here's the code and the little main method I'm using to drive it. Any suggestions of streamlining the algorithm itself would also be welcome.
public class DynamicCoinChange {
public static void main(String[] args) {
int[] denoms = {1, 6, 10, 25};
int numCoins = dynamicCoinChange(denoms, 18, 3);
System.out.println(numCoins);
}
public static int dynamicCoinChange(int[] denoms, int amt, int start) {
if (amt == 0 || start < 0) {
return 0;
} else if (amt == 1) {
return 1;
} else if (denoms[start] > amt ||
dynamicCoinChange(denoms, amt, start-1) <
(1 + dynamicCoinChange(denoms, amt-denoms[start], start)) &&
!(dynamicCoinChange(denoms, amt, start-1) == 0)) {
return dynamicCoinChange(denoms, amt, start-1);
} else {
return 1 + dynamicCoinChange(denoms,amt-denoms[start], start);
}
}
}
We need to know two pieces of information:
when a coin is chosen for the optimal solution
which coin was chosen for the optimal solution
According to your algorithm, we know that we select a coin whenever you return 1. We also know that the coin chosen at that the index of the coin chosen is start. Thus, we have information to solve this problem.
Since performance isn't a problem here, we will simply pass a coins parameter that is filled as the coins are selected.
public static int dynamicCoinChange(int[] denoms, int amt, int start, ArrayList<Integer> coins) {
if (amt == 0 || start < 0) {
return 0;
} else if (amt == 1) {
coins.add(1);
return 1;
} else if (denoms[start] > amt
// Note that these calls are not guaranteed to be in our solution
// Thus, we make a copy to prevent the calls from modifying our solution
|| dynamicCoinChange(denoms, amt, start-1, new ArrayList<Integer>(coins)) <
(1 + dynamicCoinChange(denoms, amt-denoms[start], start, new ArrayList<Integer>(coins)))
&& !(dynamicCoinChange(denoms, amt, start-1, new ArrayList<Integer>(coins)) == 0)) {
return dynamicCoinChange(denoms, amt, start-1, coins);
} else {
coins.add(denoms[start]);
return 1 + dynamicCoinChange(denoms,amt-denoms[start], start, coins);
}
}
Since this requires us to change our method signature, we must also modify our driver:
public static void main(String[] args) {
int[] denoms = {1, 6, 10, 25};
ArrayList<Integer> coins = new ArrayList<Integer>();
int numCoins = dynamicCoinChange(denoms, 7, 3, coins);
for (Integer coin : coins)
System.out.println(coin);
System.out.println(numCoins);
}
At the end of the recursive calls, coins should contain the list of coins chosen in chronological order.
The Minimum Change problem need not be programmed recursively. It can be programmed in a simpler iterative fashion.
int[] denoms = { 1, 6, 10, 25 };
int amt = 18;
double[] min = new double[ amt + 1 ];
for( int i = 1; i < min.length; i++ ) { // We're keeping min[ 0 ] as 0/
min[ i ] = Double.POSITIVE_INFINITY;
}
for( int i = 1; i <= amt; i++ ) {
for( int j = 0; j <= N - 1; j++ ) {
if( denoms[ j ] <= i && min[ i - denoms[ j ] ] + 1 < min[ i ] )
min[ i ] = min[ i - denoms[ j ] ] + 1;
}
}
Here, your solution would be in entry min[amt].