Related
Recently, In a competitive coding exam I got this question -
A good number is number whose sum of digits is divisible by 5. example - 5 (5), 14 (1+4), 19(1+9), 23(2+3)
Question is - you are provided a integer n and another integer k you have to find kth good number greater the n.
Constraints - 1<k<10^9
Sample test 1 -
input: n = 6, k = 5
output: 32
Explanation: After 6 good numbers are - 14, 19, 23, 28, 32 (5th is 32)
Sample test 2 -
input: n = 5, k = 1
output: 14
Explanation: 5 is 1st good number but we need greater than 5 so ans is 14
I have tried it with native approach i.e for each number greater then n checking if it is good and loop until I found k good numbers, here is my code -
def solve(n,k):
n+=1
count = 0
while count<k:
if sum(map(int,str(n)))%5==0:
count+=1
n+=1
return n-1
but above code was gave me TLE, how to do it in better time complexity, I have searched on internet for similar question but unable to find, help.
Let's start with a simple question:
I give you a list of five consecutive numbers. How many of those numbers are divisible by 5? (I'm not talking abouts sums of digits yet. Just the numbers, like 18, 19, 20, 21, 22.
No problem there, right? So a slightly different question:
In a list of ten consecutive numbers, how many are divisible by 5?
Still pretty easy, no? Now let's look at your "good" numbers. We'll start by introducing the function digit_sum(n), which is the sum of the digits in n. For now, we don't need to write that function; we just need to know it exists. And here's another simple question:
If n is a number which does not end in the digit 9 and s is digit_sum(n), what is digit_sum(n+1)? (Try a few numbers if that's not immediately clear.) (Bonus question: why does it matter whether the last digit is 9? Or to put it another way, why doesn't it matter which digit other than 9 is at the end? What's special about 9?)
Ok, almost there. Let's put these two ideas together:
Suppose n ends with 0. How many of the ten numbers digit_sum(n), digit_sum(n+1), digit_sum(n+2), … digit_sum(n+9) are divisible by 5? (See question 2).
Does that help you find a quick way to compute the kth good number after n? Hopefully, the answer is yes. Now you just need to generalise a little bit.
maybe your digits algorithm is too time consuming? try this:
def digits(n):
sum = 0
while n:
n, r = divmod(n, 10)
sum += r
return sum
def solve(n,k):
n+=1
count = 0
while count<k:
if digits(n)%5==0:
count+=1
n+=1
return n-1
still it’s a trivial solution, and always you can run it offline and just submit a lookups table.
And here is a link for this sequence: http://oeis.org/A227793
Here's a digit dynamic-program that can answer how many such numbers we can find from 1 to the parameter, k. The function uses O(num_digits) search space. We could use it to search for the kth good number with binary search.
The idea generally is that the number of good numbers that include digit d in the ith position, and have a prefix mod 5 of mod1 so far, is equal to the count of valid digit-suffixes that have the complementary mod, mod2, so that (mod1 + mod2) mod 5 = 0.
JavaScript code comparing with brute force:
function getDigits(k){
const result = [];
while (k){
result.push(k % 10);
k = ~~(k / 10);
}
return result.reverse();
}
function g(i, mod, isK, ds, memo){
const key = String([i, mod, isK]);
if (memo.hasOwnProperty(key))
return memo[key];
let result = 0;
const max = isK ? ds[i] : 9;
// Single digit
if (i == ds.length-1){
for (let j=0; j<=max; j++)
result += (j % 5 == mod);
return memo[key] = result;
}
// Otherwise
for (let j=0; j<=max; j++){
const m = j % 5;
const t = (5 + mod - m) % 5;
const next = g(i+1, t, isK && j == max, ds, memo);
result += next;
}
return memo[key] = result;
}
function f(k){
if (k < 10)
return (k > 4) & 1;
const ds = getDigits(k);
const memo = {};
let result = -1;
for (let i=0; i<=ds[0]; i++){
const m = i % 5;
const t = (5 - m) % 5;
const next = g(1, t, i==ds[0], ds, memo);
result += next;
}
return result;
}
function bruteForce(k){
let result = 0;
//let ns = [];
for (let i=1; i<=k; i++){
const ds = getDigits(i);
const sum = ds.reduce((a, b) => a + b, 0);
if (!(sum % 5)){
//ns.push(i);
result += 1;
}
}
//console.log(ns);
return result;
}
var k = 3000;
for (let i=1; i<k; i++){
const _bruteForce = bruteForce(i);
const _f = f(i);
if (_bruteForce != _f){
console.log(i);
console.log(_bruteForce);
console.log(_f);
break;
}
}
console.log('Done.');
Given a list of N coins, their values (V1, V2, ... , VN), and the total sum S. Find the minimum number of coins the sum of which is S (we can use as many coins of one type as we want), or report that it's not possible to select coins in such a way that they sum up to S.
I try to understand dynamic programming, haven't figured it out. I don't understand the given explanation, so maybe you can throw me a few hints how to program this task? No code, just ideas where I should start.
Thanks.
The precise answer to this problem is well explained here.
http://www.topcoder.com/tc?module=Static&d1=tutorials&d2=dynProg
This is a classic Knapsack problem, take a look here for some more information: Wikipedia Knapsack Problem
You should also look at some sorting, specifically sorting from Largest to Smallest values.
As already pointed out, Dynamic Programming suits best for this problem. I have written a Python program for this:-
def sumtototal(total, coins_list):
s = [0]
for i in range(1, total+1):
s.append(-1)
for coin_val in coins_list:
if i-coin_val >=0 and s[i-coin_val] != -1 and (s[i] > s[i-coin_val] or s[i] == -1):
s[i] = 1 + s[i-coin_val]
print s
return s[total]
total = input()
coins_list = map(int, raw_input().split(' '))
print sumtototal(total, coins_list)
For input:
12
2 3 5
The output would be:
[0, -1, 1, 1, 2, 1, 2, 2, 2, 3, 2, 3, 3]
3
The list_index is the total needed and the value at list_index is the no. of coins needed to get that total. The answer for above input(getting a value 12) is 3 ( coins of values 5, 5, 2).
I think the approach you want is like this:
You know that you want to produce a sum S. The only ways to produce S are to first produce S-V1, and then add a coin of value V1; or to produce S-V2 and then add a coin of value V2; or...
In turn, T=S-V1 is producible from T-V1, or T-V2, or...
By stepping back in this way, you can determine the best way, if any, to produce S from your Vs.
Question is already answered but I wanted to provide working C code that I wrote, if it helps anyone. enter code here
Code has hard coded input, but it is just to keep it simple. Final solution is the array min containing the number of coins needed for each sum.
#include"stdio.h"
#include<string.h>
int min[12] = {100};
int coin[3] = {1, 3, 5};
void
findMin (int sum)
{
int i = 0; int j=0;
min [0] = 0;
for (i = 1; i <= sum; i++) {
/* Find solution for Sum = 0..Sum = Sum -1, Sum, i represents sum
* at each stage */
for (j=0; j<= 2; j++) {
/* Go over each coin that is lesser than the sum at this stage
* i.e. sum = i */
if (coin[j] <= i) {
if ((1 + min[(i - coin[j])]) <= min[i]) {
/* E.g. if coin has value 2, then for sum i = 5, we are
* looking at min[3] */
min[i] = 1 + min[(i-coin[j])];
printf("\nsetting min[%d] %d",i, min[i]);
}
}
}
}
}
void
initializeMin()
{
int i =0;
for (i=0; i< 12; i++) {
min[i] = 100;
}
}
void
dumpMin()
{
int i =0;
for (i=0; i< 12; i++) {
printf("\n Min[%d]: %d", i, min[i]);
}
}
int main()
{
initializeMin();
findMin(11);
dumpMin();
}
I don't know about dynamic programming but this is how I would do it. Start from zero and work your way to S. Produce a set with one coin, then with that set produce a two-coin set, and so on... Search for S, and ignore all values greater than S. For each value remember the number of coins used.
Lots of people already answered the question. Here is a code that uses DP
public static List<Integer> getCoinSet(int S, int[] coins) {
List<Integer> coinsSet = new LinkedList<Integer>();
if (S <= 0) return coinsSet;
int[] coinSumArr = buildCoinstArr(S, coins);
if (coinSumArr[S] < 0) throw new RuntimeException("Not possible to get given sum: " + S);
int i = S;
while (i > 0) {
int coin = coins[coinSumArr[i]];
coinsSet.add(coin);
i -= coin;
}
return coinsSet;
}
public static int[] buildCoinstArr(int S, int[] coins) {
Arrays.sort(coins);
int[] result = new int[S + 1];
for (int s = 1; s <= S; s++) {
result[s] = -1;
for (int i = coins.length - 1; i >= 0; i--) {
int coin = coins[i];
if (coin <= s && result[s - coin] >= 0) {
result[s] = i;
break;
}
}
}
return result;
}
The main idea is - for each coin j, value[j] <= i (i.e sum) we look at the minimum number of coins found for i-value[j] (let say m) sum (previously found). If m+1 is less than the minimum number of coins already found for current sum i then we update the number of coins in the array.
For ex - sum = 11 n=3 and value[] = {1,3,5}
Following is the output we get
i- 1 mins[i] - 1
i- 2 mins[i] - 2
i- 3 mins[i] - 3
i- 3 mins[i] - 1
i- 4 mins[i] - 2
i- 5 mins[i] - 3
i- 5 mins[i] - 1
i- 6 mins[i] - 2
i- 7 mins[i] - 3
i- 8 mins[i] - 4
i- 8 mins[i] - 2
i- 9 mins[i] - 3
i- 10 mins[i] - 4
i- 10 mins[i] - 2
i- 11 mins[i] - 3
As we can observe for sum i = 3, 5, 8 and 10 we improve upon from our previous minimum in following ways -
sum = 3, 3 (1+1+1) coins of 1 to one 3 value coin
sum = 5, 3 (3+1+1) coins to one 5 value coin
sum = 8, 4 (5+1+1+1) coins to 2 (5+3) coins
sum = 10, 4 (5+3+1+1) coins to 2 (5+5) coins.
So for sum=11 we will get answer as 3(5+5+1).
Here is the code in C. Its similar to pseudocode given in topcoder page whose reference is provided in one of the answers above.
int findDPMinCoins(int value[], int num, int sum)
{
int mins[sum+1];
int i,j;
for(i=1;i<=sum;i++)
mins[i] = INT_MAX;
mins[0] = 0;
for(i=1;i<=sum;i++)
{
for(j=0;j<num;j++)
{
if(value[j]<=i && ((mins[i-value[j]]+1) < mins[i]))
{
mins[i] = mins[i-value[j]] + 1;
printf("i- %d mins[i] - %d\n",i,mins[i]);
}
}
}
return mins[sum];
}
int getMinCoins(int arr[],int sum,int index){
int INFINITY=1000000;
if(sum==0) return 0;
else if(sum!=0 && index<0) return INFINITY;
if(arr[index]>sum) return getMinCoins(arr, sum, index-1);
return Math.min(getMinCoins(arr, sum, index-1), getMinCoins(arr, sum-arr[index], index-1)+1);
}
Consider i-th coin. Either it will be included or not. If it is included, then the value sum is decreased by the coin value and the number of used coins increases by 1. If it is not included, then we need to explore the remaining coins similarly. We take the minimum of two cases.
I knew this is a old question, but this is a solution in Java.
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class MinCoinChange {
public static void min(int[] coins, int money) {
int[] dp = new int[money + 1];
int[] parents = new int[money + 1];
int[] usedCoin = new int[money + 1];
Arrays.sort(coins);
Arrays.fill(dp, Integer.MAX_VALUE);
Arrays.fill(parents, -1);
dp[0] = 0;
for (int i = 1; i <= money; ++i) {
for (int j = 0; j < coins.length && i >= coins[j]; ++j) {
if (dp[i - coins[j]] + 1 < dp[i]) {
dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
parents[i] = i - coins[j];
usedCoin[i] = coins[j];
}
}
}
int parent = money;
Map<Integer, Integer> result = new HashMap<>();
while (parent != 0) {
result.put(usedCoin[parent], result.getOrDefault(usedCoin[parent], 0) + 1);
parent = parents[parent];
}
System.out.println(result);
}
public static void main(String[] args) {
int[] coins = { 1, 5, 10, 25 };
min(coins, 30);
}
}
For a fast recursive solution, you can check this link: java solution
I am going through the minimum steps required to find the perfect coin combination.
Say we have coins = [20, 15, 7] and monetaryValue = 37. My solution will work as follow:
[20] -> sum of array bigger than 37? NO -> add it to itself
[20, 20] greater than 37? YES (20 + 20) -> remove last and jump to smaller coin
[20, 15] 35 OK
[20, 15, 15] 50 NO
[20, 15, 7] 42 NO
// Replace biggest number and repeat
[15] 15 OK
[15, 15] 30 OK
[15, 15, 15] 45 NO
[15, 15, 7] 37! RETURN NUMBER!
def leastCoins(lst, x):
temp = []
if x == 0:
return 0
else:
while x != 0:
if len(lst) == 0:
return "Not Possible"
if x % max(lst) == 0:
temp.append((max(lst), x//max(lst)))
x = 0
elif max(lst) < x:
temp.append((max(lst), x//max(lst)))
x = x % max(lst)
lst.remove(max(lst))
else:
lst.remove(max(lst))
return dict(temp)
leastCoins([17,18,2], 100652895656565)
So I want to know how to count all the solutions for a knapsack problem. Namely I'm interested in finding the number of possible subsets from a set of numbers that have the maximum size of K.
e.g we have a set of items of size {3, 2, 5, 6, 7} and the max size is K = 13. So the solutions are {5, 6, 2} and {6, 7}. On the other hand there are two solutions; I want my dynamic programming algorithm to report there are two possible solutions.
This can be done with dynamic programming. The basic strategy is to build a memorization table, d[i][j], which stores the number of combinations using the first j numbers that sum to i. Note that j = 0 represents an empty set of numbers. Here is a sample implementation:
int countCombinations(int[] numbers, int target) {
// d[i][j] = n means there are n combinations of the first j numbers summing to i.
int[][] d = new int[target + 1][numbers.length + 1];
// There is always 1 combination summing to 0, namely the empty set.
for (int j = 0; j <= numbers.length; ++j) {
d[0][j] = 1;
}
// For each total i, calculate the effect of using or omitting each number j.
for (int i = 1; i <= target; ++i) {
for (int j = 1; j <= numbers.length; ++j) {
// "First j numbers" is 1-indexed, our array is 0-indexed.
int number = numbers[j - 1];
// Initialize value to 0.
d[i][j] = 0;
// How many combinations were there before considering the jth number?
d[i][j] += d[i][j - 1];
// How many things summed to i - number?
if (i - number >= 0) {
d[i][j] += d[i - number][j - 1];
}
}
}
// Return the entry in the table storing all the number combos summing to target.
return d[target][numbers.length - 1];
}
Just to add some Google keywords: this problem is also known as summing n coins without repeats to a target sum.
There is a dynamic knapsack solution for this task.In dp array dp[i] stores the number of subsets which their sum is "i". In this case your answer is dp[K].( Sorry for indentation problems I could not figure out how to make it right :( )
dp[0] = 1 ;
for( int i=0; i<N ; i++ )
for( int j=K-a[i] ; j>=0 ; j-- )
dp[j+a[i]] += dp[j]
I don't think Max's algorithm works for the case: [0,0,1] with target of 1. The answer is 4 but his algorithm will output 1. His algorithm only works for positive integers, because it assumes that a sum of 0 can only be achieved with empty set. However, it can also be achieved if 0 exists in the array. The more robust way of tackling this problem (and also more space efficient) is using a 1D dp array. The pseudo-code is the following:
int[] dp = new int[target+1];
for (int num : nums) {
for (int s = target; s >= 0; s--) {
if (s >= num) { // can include num
dp[s] += dp[s-num];
} else { // cannot include num (can be omitted, here for better explanation)
dp[s] += 0;
}
}
}
return dp[target+1];
The reason I backtrack from target to 0 in the inner for loop is to avoid duplication. Think about the example [2,2,2] with target sum of 4. If you iterate from index 0, then you would double count a 2 when you are at dp[4] (should be [1 0 1 0 0] instead of [1 0 1 0 1] after one iteration in inner loop).
Hope this helps.
It's a programming puzzle which goes like: "A number is said to be brilliant if the product of all digits of its substrings have a unique value."
Example : 263 (2, 6, 3, 2*6 = 12, 6*3 = 18) is brilliant.
But 236 (2, 3, 6, 2*3 = 6, 3*6 = 18) is not brilliant.
We take only substrings, not subsequences.
I was thinking maybe we can apply Dynamic Programming here because of repeated product calculations? What other solutions can we have for it? (This isn't a homework question.)
Here's one way of solving it using dynamic programming:
Assume we have the number d0 d1 ... dN as input.
The idea is to create a table, where cell (i, j) store the product di · di+1 · ... · dj. This can be done efficiently since the cell at (i, j) can be computed by multiplying the number at (i-1, j) by di.
Since i (the start index) must be less than or equal to j (the end index), we'll focus on the lower left triangle of the table.
After generating the table, we check for duplicate entries.
Here's a concrete example solution for input 2673:
We allocate a matrix, M, with dimensions 4 × 4.
We start by filling in the diagonals, Mi,i with di:
We then go row by row, and fill in Mi,j with di ·Mi-1,j
The result looks like
To check for duplicates, we collect the products (2, 12, 6, 84, 42, 7, 252, 126, 21, 3), sort them (2, 3, 6, 7, 12, 21, 42, 84, 126, 252), and loop through to see if two consecutive numbers are equal. If so we return false, otherwise true.
In Java code:
Here's a working DP solution, O(n2).
public static boolean isColorful(int num) {
// Some initialization
String str = "" + num;
int[] digits = new int[str.length()];
for (int i = 0; i < str.length(); i++)
digits[i] = str.charAt(i) - '0';
int[][] dpmatrix = new int[str.length()][str.length()];
// Fill in diagonal: O(N)
for (int i = 0; i < digits.length; i++)
dpmatrix[i][i] = digits[i];
// Fill in lower left triangle: O(N^2)
for (int i = 0; i < str.length(); i++)
for (int j = 0; j < i; j++)
dpmatrix[i][j] = digits[i] * dpmatrix[i-1][j];
// Check for dups: O(N^2)
int[] nums = new int[digits.length * (digits.length+1) / 2];
for (int i = 0, j = 0; i < digits.length; i++, j += i)
System.arraycopy(dpmatrix[i], 0, nums, j, i+1);
Arrays.sort(nums);
for (int i = 0; i < nums.length - 1; i++)
if (nums[i] == nums[i+1])
return false;
return true;
}
For DP-interested readers I can recommend the somewhat similar question/answer over here:
Find the number of occurrences of a subsequence in a string
Using dynamic programming is probably the way to go:
Instead of calculating all O(n^2) substrings, and then using ~n multiplication commands to calculate each of them, store the results of previous caclulation in a matrix M, where M(i,j) is the result of the substring of length j, starting from position i.
(i.e, if your number is 123456789, then M(1,5) is 5!, and M(1,6) is 6!, which only requires multiplying M(1,5) by 6 - constant work)
This will improve the running time from O(n^3) for n digits to O(n^2).
A dynamic programming solution is really not necessary, as there are no brilliant numbers with a large number of digits (if any digit appears more than once, the number is not brilliant).
Here is a list of every brilliant number. There are 57,281 total.
This file took less than a second to generate on my PC, even without using dynamic programming :)
if we don't consider the number as a large string then hashing can help;
int brill(int A) {
map<long long int,bool> m;
vector<int> arr(10,0);
int i=0;
while(A){
arr[i++]=A%10;
A/=10;
}
for(int j=0;j<i;j++){
long long int temp=1;
for(int k=j;k>=0;k--){
temp*=arr[k];
if(m.find(temp)!=m.end()){
return 0;
}
else{
m[temp]=true;
}
}
}
return 1;
}
n is the string containing the number.
Since the number can't be greater than 8 digits before a failure state its O(1).
function isBrill(n) {
var set = {};
set[parseInt(n.charAt(0))] = true;
for(var i=0; i < n.length - 1; i++) {
var a = parseInt(n.charAt(i));
var b = parseInt(n.charAt(i+1));
if(set[b] === true) { return false; }
set[b] = true;
if(set[a * b] === true) { return false; }
set[a * b] = true;
}
return true;
}
isBrill("263"); // true
isBrill("236"); // false
Given a list of N coins, their values (V1, V2, ... , VN), and the total sum S. Find the minimum number of coins the sum of which is S (we can use as many coins of one type as we want), or report that it's not possible to select coins in such a way that they sum up to S.
I try to understand dynamic programming, haven't figured it out. I don't understand the given explanation, so maybe you can throw me a few hints how to program this task? No code, just ideas where I should start.
Thanks.
The precise answer to this problem is well explained here.
http://www.topcoder.com/tc?module=Static&d1=tutorials&d2=dynProg
This is a classic Knapsack problem, take a look here for some more information: Wikipedia Knapsack Problem
You should also look at some sorting, specifically sorting from Largest to Smallest values.
As already pointed out, Dynamic Programming suits best for this problem. I have written a Python program for this:-
def sumtototal(total, coins_list):
s = [0]
for i in range(1, total+1):
s.append(-1)
for coin_val in coins_list:
if i-coin_val >=0 and s[i-coin_val] != -1 and (s[i] > s[i-coin_val] or s[i] == -1):
s[i] = 1 + s[i-coin_val]
print s
return s[total]
total = input()
coins_list = map(int, raw_input().split(' '))
print sumtototal(total, coins_list)
For input:
12
2 3 5
The output would be:
[0, -1, 1, 1, 2, 1, 2, 2, 2, 3, 2, 3, 3]
3
The list_index is the total needed and the value at list_index is the no. of coins needed to get that total. The answer for above input(getting a value 12) is 3 ( coins of values 5, 5, 2).
I think the approach you want is like this:
You know that you want to produce a sum S. The only ways to produce S are to first produce S-V1, and then add a coin of value V1; or to produce S-V2 and then add a coin of value V2; or...
In turn, T=S-V1 is producible from T-V1, or T-V2, or...
By stepping back in this way, you can determine the best way, if any, to produce S from your Vs.
Question is already answered but I wanted to provide working C code that I wrote, if it helps anyone. enter code here
Code has hard coded input, but it is just to keep it simple. Final solution is the array min containing the number of coins needed for each sum.
#include"stdio.h"
#include<string.h>
int min[12] = {100};
int coin[3] = {1, 3, 5};
void
findMin (int sum)
{
int i = 0; int j=0;
min [0] = 0;
for (i = 1; i <= sum; i++) {
/* Find solution for Sum = 0..Sum = Sum -1, Sum, i represents sum
* at each stage */
for (j=0; j<= 2; j++) {
/* Go over each coin that is lesser than the sum at this stage
* i.e. sum = i */
if (coin[j] <= i) {
if ((1 + min[(i - coin[j])]) <= min[i]) {
/* E.g. if coin has value 2, then for sum i = 5, we are
* looking at min[3] */
min[i] = 1 + min[(i-coin[j])];
printf("\nsetting min[%d] %d",i, min[i]);
}
}
}
}
}
void
initializeMin()
{
int i =0;
for (i=0; i< 12; i++) {
min[i] = 100;
}
}
void
dumpMin()
{
int i =0;
for (i=0; i< 12; i++) {
printf("\n Min[%d]: %d", i, min[i]);
}
}
int main()
{
initializeMin();
findMin(11);
dumpMin();
}
I don't know about dynamic programming but this is how I would do it. Start from zero and work your way to S. Produce a set with one coin, then with that set produce a two-coin set, and so on... Search for S, and ignore all values greater than S. For each value remember the number of coins used.
Lots of people already answered the question. Here is a code that uses DP
public static List<Integer> getCoinSet(int S, int[] coins) {
List<Integer> coinsSet = new LinkedList<Integer>();
if (S <= 0) return coinsSet;
int[] coinSumArr = buildCoinstArr(S, coins);
if (coinSumArr[S] < 0) throw new RuntimeException("Not possible to get given sum: " + S);
int i = S;
while (i > 0) {
int coin = coins[coinSumArr[i]];
coinsSet.add(coin);
i -= coin;
}
return coinsSet;
}
public static int[] buildCoinstArr(int S, int[] coins) {
Arrays.sort(coins);
int[] result = new int[S + 1];
for (int s = 1; s <= S; s++) {
result[s] = -1;
for (int i = coins.length - 1; i >= 0; i--) {
int coin = coins[i];
if (coin <= s && result[s - coin] >= 0) {
result[s] = i;
break;
}
}
}
return result;
}
The main idea is - for each coin j, value[j] <= i (i.e sum) we look at the minimum number of coins found for i-value[j] (let say m) sum (previously found). If m+1 is less than the minimum number of coins already found for current sum i then we update the number of coins in the array.
For ex - sum = 11 n=3 and value[] = {1,3,5}
Following is the output we get
i- 1 mins[i] - 1
i- 2 mins[i] - 2
i- 3 mins[i] - 3
i- 3 mins[i] - 1
i- 4 mins[i] - 2
i- 5 mins[i] - 3
i- 5 mins[i] - 1
i- 6 mins[i] - 2
i- 7 mins[i] - 3
i- 8 mins[i] - 4
i- 8 mins[i] - 2
i- 9 mins[i] - 3
i- 10 mins[i] - 4
i- 10 mins[i] - 2
i- 11 mins[i] - 3
As we can observe for sum i = 3, 5, 8 and 10 we improve upon from our previous minimum in following ways -
sum = 3, 3 (1+1+1) coins of 1 to one 3 value coin
sum = 5, 3 (3+1+1) coins to one 5 value coin
sum = 8, 4 (5+1+1+1) coins to 2 (5+3) coins
sum = 10, 4 (5+3+1+1) coins to 2 (5+5) coins.
So for sum=11 we will get answer as 3(5+5+1).
Here is the code in C. Its similar to pseudocode given in topcoder page whose reference is provided in one of the answers above.
int findDPMinCoins(int value[], int num, int sum)
{
int mins[sum+1];
int i,j;
for(i=1;i<=sum;i++)
mins[i] = INT_MAX;
mins[0] = 0;
for(i=1;i<=sum;i++)
{
for(j=0;j<num;j++)
{
if(value[j]<=i && ((mins[i-value[j]]+1) < mins[i]))
{
mins[i] = mins[i-value[j]] + 1;
printf("i- %d mins[i] - %d\n",i,mins[i]);
}
}
}
return mins[sum];
}
int getMinCoins(int arr[],int sum,int index){
int INFINITY=1000000;
if(sum==0) return 0;
else if(sum!=0 && index<0) return INFINITY;
if(arr[index]>sum) return getMinCoins(arr, sum, index-1);
return Math.min(getMinCoins(arr, sum, index-1), getMinCoins(arr, sum-arr[index], index-1)+1);
}
Consider i-th coin. Either it will be included or not. If it is included, then the value sum is decreased by the coin value and the number of used coins increases by 1. If it is not included, then we need to explore the remaining coins similarly. We take the minimum of two cases.
I knew this is a old question, but this is a solution in Java.
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class MinCoinChange {
public static void min(int[] coins, int money) {
int[] dp = new int[money + 1];
int[] parents = new int[money + 1];
int[] usedCoin = new int[money + 1];
Arrays.sort(coins);
Arrays.fill(dp, Integer.MAX_VALUE);
Arrays.fill(parents, -1);
dp[0] = 0;
for (int i = 1; i <= money; ++i) {
for (int j = 0; j < coins.length && i >= coins[j]; ++j) {
if (dp[i - coins[j]] + 1 < dp[i]) {
dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
parents[i] = i - coins[j];
usedCoin[i] = coins[j];
}
}
}
int parent = money;
Map<Integer, Integer> result = new HashMap<>();
while (parent != 0) {
result.put(usedCoin[parent], result.getOrDefault(usedCoin[parent], 0) + 1);
parent = parents[parent];
}
System.out.println(result);
}
public static void main(String[] args) {
int[] coins = { 1, 5, 10, 25 };
min(coins, 30);
}
}
For a fast recursive solution, you can check this link: java solution
I am going through the minimum steps required to find the perfect coin combination.
Say we have coins = [20, 15, 7] and monetaryValue = 37. My solution will work as follow:
[20] -> sum of array bigger than 37? NO -> add it to itself
[20, 20] greater than 37? YES (20 + 20) -> remove last and jump to smaller coin
[20, 15] 35 OK
[20, 15, 15] 50 NO
[20, 15, 7] 42 NO
// Replace biggest number and repeat
[15] 15 OK
[15, 15] 30 OK
[15, 15, 15] 45 NO
[15, 15, 7] 37! RETURN NUMBER!
def leastCoins(lst, x):
temp = []
if x == 0:
return 0
else:
while x != 0:
if len(lst) == 0:
return "Not Possible"
if x % max(lst) == 0:
temp.append((max(lst), x//max(lst)))
x = 0
elif max(lst) < x:
temp.append((max(lst), x//max(lst)))
x = x % max(lst)
lst.remove(max(lst))
else:
lst.remove(max(lst))
return dict(temp)
leastCoins([17,18,2], 100652895656565)