Compute the different ways to make (money) change from $167.37? - java

This was an interview question:
Given an amount, say $167.37 find all the possible ways of generating the change for this amount using the denominations available in the currency?
Anyone who could think of a space and time efficient algorithm and supporting code, please share.
Here is the code that i wrote (working) . I am trying to find the running time of this, any help is appreciated
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
public class change_generation {
/**
* #param args
*/
public static void generatechange(float amount,LinkedList<Float> denominations,HashMap<Float,Integer> useddenominations)
{
if(amount<0)
return;
if(amount==0)
{
Iterator<Float> it = useddenominations.keySet().iterator();
while(it.hasNext())
{
Float val = it.next();
System.out.println(val +" :: "+useddenominations.get(val));
}
System.out.println("**************************************");
return;
}
for(Float denom : denominations)
{
if(amount-denom < 0)
continue;
if(useddenominations.get(denom)== null)
useddenominations.put(denom, 0);
useddenominations.put(denom, useddenominations.get(denom)+1);
generatechange(amount-denom, denominations, useddenominations);
useddenominations.put(denom, useddenominations.get(denom)-1);
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
float amount = 2.0f;
float nikle=0.5f;
float dollar=1.0f;
float ddollar=2.0f;
LinkedList<Float> denominations = new LinkedList<Float>();
denominations.add(ddollar);
denominations.add(dollar);
denominations.add(nikle);
HashMap<Float,Integer> useddenominations = new HashMap<Float,Integer>();
generatechange(amount, denominations, useddenominations);
}
}

EDIT
This is a specific example of the combination / subset problem, answered here.
Finding all possible combinations of numbers to reach a given sum
--- I am retaining my answer below (as it was usefull to someone), however, admittedly, it is not a direct answer to this question ---
ORIGINAL ANSWER
The most common solution is dynamic programming :
First, you find the simplest way to make change of 1, then you use that solution to make change for 2, 3, 4, 5, 6, etc.... At each iteration, you "check" if you can go "backwards" and decrease the amount of coins in your answer. For example, up to "4" you must add pennies. But, once you get to "5", you can remove all pennies, and your solution has only one coin required : the nickel. But then, until 9, you again must add pennies, etc etc etc.
However, the dynamic programming methodology is not gauranteed to be fast.
Alternatively, you can use a greedy method, where you continually pick the largest coin possible. This is extremely fast , but doesnt always give you an optimal solution. However, if your coins are 1 5 10 and 25 , Greedy works perfectly, and is much faster then the linear programming method.

Memoization (kind of) is your friend here. A simple implementation in C:
unsigned int findRes(int n)
{
//Setup array, etc.
//Only one way to make zero... no coins.
results[0] = 1;
for(i=0; i<number_of_coins; i++)
{
for(j=coins[i]; j<=n; j++)
{
results[j] += results[j - coins[i]];
}
}
return results[n];
}
So, what we're really doing here is saying:
1) Our only possible way to make 0 coins is 0 (this is our base case)
2) If we are trying to calculate value m, then let's check each coin k. As long as k <= m, we can use that coin k in a solution
3) Well, if we can use k in a solution, then couldn't we just take the solution for (m-k) and add it to our current total?

I'd try to model this in real life.
If you were at the till and you knew you had to find $167.37 you would probably initially consider $200 as the "simplest" tender, being just two notes. Then, if I had it, I may consider $170, i.e. $100, $50 and $20 (three notes). See where I am going?
More formally, try to over-tender with the minimum number of notes/coins. This would be much easier to enumerate than the full set of possibilities.

Don't use floats, even tiniest inaccuracies will destroy your algorithm.
Go from biggest to lowest coin/banknote. For every possible amount call the function recursively. When there are no more coins left pay the rest in ones and print the solution. This is how it looks in pseudo-C:
#define N 14
int coinValue[N]={20000,10000,5000,2000,1000,500,200,100,50,20,10,5,2,1};
int coinCount[N];
void f(int toSpend, int i)
{
if(coinValue[i]>1)
{
for(coinCount[i]=0;coinCount[i]*coinValue[i]<=toSpend;coinCount[i]++)
{
f(toSpend-coinCount[i]*coinValue[i],i+1);
}
}
else
{
coinCount[i]=toSpend;
print(coinCount);
}
}

import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
public class change_generation {
static int jj=1;
public static void generatechange(float amount,LinkedList<Float> denominations,
HashMap<Float,Integer> useddenominations) {
if(amount<0)
return;
if(amount==0) {
Iterator<Float> it = useddenominations.keySet().iterator();
while(it.hasNext()) {
Float val = it.next();
System.out.println(val +" :: "+useddenominations.get(val));
}
System.out.println("**************************************");
return;
}
for(Float denom : denominations) {
if(amount-denom < 0)
continue;
if(useddenominations.get(denom)== null)
useddenominations.put(denom, 0);
useddenominations.put(denom, useddenominations.get(denom)+1);
generatechange(amount-denom, denominations, useddenominations);
useddenominations.put(denom, useddenominations.get(denom)-1);
}
}
public static void main(String[] args) {
float amount = 2.0f;
float nikle=0.25f;
float dollar=1.0f;
float ddollar=2.0f;
LinkedList<Float> denominations = new LinkedList<Float>();
denominations.add(ddollar);
denominations.add(dollar);
denominations.add(nikle);
HashMap<Float,Integer> useddenominations = new HashMap<Float,Integer>();
generatechange(amount, denominations, useddenominations);
}
}

Related

Find the lowest and highest NUMBERS in a collection

I have a List<BigDecimal> collection which contains (for the sake of simplicity) BigDecimal prices. I would like to process the collection and get:
All of the highest prices.
All of the lowest prices.
My initial thoughts are to approach this using look-behind in order to decide if the numbers are moving in an up or down trend. When the trend changes - determine which of the previous numbers are "highest" or "lowest" prices and then add them to the respectful List<BigDecimal> lowestPrices and List<BigDecimal highestPrices collections. For example, the first 3 dots are in an up-trend, but the 4th changes the trend to a down-trend. So can now determine the min/max of the numbers before the change (0,1,2) and get the prices.
I am not entirely sure if this isn't a naive approach so I was wondering if there would be the best approach to solving this issue in java?
Maybe a library that can already do this? (probably better not to re-invent the wheel)
You are looking for local maxima (/minima).
Just look at whether the current point is greater (/less) than the point preceding and following it:
For a local maximum:
list.get(i) > list.get(i - 1) && list.get(i) > list.get(i + 1)
For a local minimum:
list.get(i) < list.get(i - 1) && list.get(i) < list.get(i + 1)
Pseudocode:
for (int i = 1; i < list.size()-1; ++i) {
if (local maximum) {
// Add to list of local maxima
} else if (local minimum) {
// Add to list of local minima
}
}
and handle the two endpoints as you desire.
(You can also do this in ways that are more efficient for non-random access lists, e.g. LinkedList, using (List)Iterators; but the principle is the same).
I decided to try implementing this, although I'm sure my implementation could be improved. The idea is just as you say, to keep track of the trend and record a local minimum or local maximum whenever the trend changes. There are two additional details to consider: first, initially we are not trending up or down, but the first value is either a minimum or maximum, so we have a third possibility for the trend, in addition to increasing or decreasing: inchoate; second, after the end of the loop we have to add the last item as either a minimum or maximum, depending on the direction the trend was going when we finished. Note that it will never add null if the list of prices is empty, because in that case, the trend would never have changed from inchoate.
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Map;
import java.util.List;
public class Partition {
public static void main(String[] args) {
List<String> values = List.of("10.99", "15.99", "19.99", "12.99", "24.99",
"21.99", "17.99", "11.99", "22.99", "29.99", "35.99", "27.99", "20.99");
List<BigDecimal> prices = values.stream().map(BigDecimal::new).toList();
Map<Extrema, List<BigDecimal>> part = new Partition().partitionExtrema(prices);
System.out.format("Minima: %s%n", part.get(Extrema.MINIMA));
System.out.format("Maxima: %s%n", part.get(Extrema.MAXIMA));
}
public Map<Extrema, List<BigDecimal>> partitionExtrema(List<BigDecimal> prices) {
Trend trend = Trend.INCHOATE; // intially we don't know if we're going up or down
List<BigDecimal> maxima = new ArrayList<>();
List<BigDecimal> minima = new ArrayList<>();
BigDecimal previous = null;
for (BigDecimal current : prices) {
int direction = previous == null ? 0 : current.compareTo(previous);
if (direction > 0) {
if (trend != Trend.DECREASING) {
minima.add(previous); // switching from decreasing to increasing
}
trend = Trend.INCREASING;
}
if (direction < 0) {
if (trend != Trend.INCREASING) {
maxima.add(previous); // switching from increasing to decreasing
}
trend = Trend.DECREASING;
}
previous = current;
}
if (trend == trend.INCREASING) {
maxima.add(previous);
} else if (trend == trend.DECREASING) {
minima.add(previous);
}
return Map.of(Extrema.MINIMA, minima, Extrema.MAXIMA, maxima);
}
}
public enum Trend {
INCREASING,
DECREASING,
INCHOATE
}
public enum Extrema {
MAXIMA,
MINIMA
}

Can some one tell me what i have done wrong

I got a question in interview about a man who can take a step back or move double of his current distance . Considering each of them as a single move find minimum moves he can take to reach y from x.
import java.util.*;
import java.io.*;
public class Main
{
public static int Solve(int x,int y)
{
if(x==0)
{
return Integer.MAX_VALUE;
}
else if(x==y)
{
return 0;
}
else if(x==1)
{
return 1+Solve(x*2,y);
}
return Math.min(1+Solve(x*2,y),1+Solve(x-1,y));
}
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
int x=sc.nextInt();
int y=sc.nextInt();
int z=Solve(x,y);
System.out.print(z);
}
}
This is an infinite loop. At what place will Solve( x * 2, y) ever
stop ?
Assuming all this is in one axis only (1D), since you defined int x and int y. Let’s say we have x and y, if y-x is positive, that means we have to go forward. Now if y-x is odd, let’s say 7 that means we have to go 8 steps (4*2) ahead, then 1 (1 step) back. Giving us 5 steps. So we have to go
(((y-x) + 1)/2) + 1
So 7+1 = 8, we go 8 steps ahead taking double steps, then 1 more step to come back.
If it is even, then that means we can go straight ahead ! So
(y-x)/2
If y-x is negative, which means we have to go back. Only way is 1 step back (x-1), so that will just be
-(y-x) steps.
You can write the code. I like the recursion aspect for your code, but it’s an overkill if it is 1D.
Not sure if a recursion-based solution is needed here.
We have two subproblems here:
count moves back when from >= to
otherwise count moves forward taking into account a case when difference to - from is odd: then 1 extra move forward is needed and 1 step back.
This can be resolved with the help of a ternary operator:
public static int findMoveCount(int from, int to) {
return from >= to ? from - to : (to - from) % 2 * 2 + (to - from)/2;
}

ThreadLocalRandom double 2 decimal

I try to print my Array Double with only 2 decimals. But I can not find in google how to do. Please any help?
package com.company;
import java.util.ArrayList;
import java.util.concurrent.ThreadLocalRandom;
public class java_05_16_05_01 {
public static void main(String[] args){
ArrayList<Double> salary=new ArrayList<Double>();
int NumberPersonSurveyed = ThreadLocalRandom.current().nextInt(1, 10+1);
for(int i=0; i<NumberPersonSurveyed; i++){
double salaryPerson = ThreadLocalRandom.current().nextDouble(1000, 10000+1);
salary.add(salaryPerson);
}
System.out.println(salary);
}
}
Actually the OUTPUT is:
[9803.056390825992,
2753.180103177606,
2602.5359323328644,
3319.2942269101018]
But I Expect:
[9803.056,
2753.18,
2602.53,
3319.29]
Note I want use ThreadLocalRandom instance of Math.random or similar.
Thanks so much!
Since you are simulating salaries, you could simply generate int values, which will be in cents, and then divide by 100 (and convert to double) to get your result.
Like so:
double salaryPerson = ThreadLocalRandom.current().nextInt(100 * 1000, 100 * (10000 + 1)) / 100d;
This approach frees you from string formatting issues, and also allows you to process your data with the exact values if you wish to perform extra operations besides printing.
There are 2 ways of doing this, the most common way I have seen is based off of the C style printf.
System.out.printf("%.2f", sal);
printf uses modifiers determined by % operators. This one specifies that it should print floating point number (the f) with 2 decimal places (the .2). You can find a list of operators here.
Personally I prefer the C# styled MessageFormat
System.out.println(MessageFormat.format("{0,number,0.00}", sal));
MessageFormat backends off of DecimalFormat which represents a number in contexts of # and 0, where a # represents a potential but not required number, while a 0 represents a required number. Which is to say if you pass 10 into the specified format it would print 10.00.
Edit:
Just realized it was an ArrayList; you're going to have to iterate through each member of the array and print them out individually.
boolean USE_PRINTF = false;
System.out.print("[");
for(int i = 0; i < salary.size(); ++i)
{
if(USE_PRINTF) { System.out.printf("%.2f", salary.get(i)); }
else { System.out.print(MessageFormat.format("{0,number,0.00}", salary.get(i))); }
if(i < salary.size() - 1) { System.out.print(", "); }
}
System.out.println("]");

How to cheaply deal with multiple ranges (finding a maximum)

I have an amount of ranges, each with a weight. Every point on the total range is scored by the sum of the weights of all the ranges the point falls into. I'd like to be able to cheaply find the total value of points, and would like to be able to find a maximum. Ideally, it would also be able to find the maximum for a set of (equidistantly) spaced points.
Unfortunately, I'm heavily limited by performance, and am struggling to find a good algorithm for this.
The only two decent solutions I could find are:
- Bruteforce it by sampling a bunch of points. For each: check every range whether it fits, find the total value, then check if it's better than the best so far. Decent point samples can be found by taking the boundaries of the ranges.
- Create a set of buckets. Iterate through all the ranges, adding a value to all the buckets that fit within the range. Then iterate through all the buckets to find the best one
Neither are fast enough for my liking (they have been tested), and the latter isn't continuous so has accuracy problems.
I'd be okay with getting a slightly inaccurate response as long as the performance is way better.
What adds a bit of extra complexity to my particular case is that I'm actually dealing with angles, so the environment is modular. The ranges can't be ordered, and I need to ensure that a range going from 340 degrees to 20 degrees contains both a point at 350 and at 10 degrees.
The angle-ranges I'm dealing with can't exceed 180 beyond degrees and only very rarely are above 90.
The amount of ranges generally isn't very high (1-30), but I need to do this calculation a lot.
The language is Java if it matters.
Make a list (array) of angle intervals. If interval finish value less than start value (20<340), add 360 to the finish (340, 380)
Make a list of pair (angle, +weight for start point or -weight for finish point).
Concatenate list with its copy to provide circular intersection. (It is possible to copy only part of list)
Sort them by angle (use +/- as secondary key in case of tie: - before +)
Make CurrWeight=0
Walk through the list, adding +/weight field to CurrWeight. Check for max value.
(Such approach works for linear lists, I tried to modify it for circular ones, perhaps I might miss some caveats)
here, instead of the term 'edges', i should have better used the term 'boundaries', because it referes to interval boundaries
import java.util.ArrayList;
import java.util.Iterator;
import java.util.SortedSet;
import java.util.TreeSet;
public class Main {
ArrayList<Interval> intervals;
public static void main(String args[]) {
Main main = new Main();
main.intervals = new ArrayList<Interval>();
Interval i1 = new Interval(10, 30, 1);
Interval i2= new Interval(20, 40, 1);
Interval i3= new Interval(50, 60, 1);
Interval i4= new Interval(0, 70, 1);
main.intervals.add(i1);
main.intervals.add(i2);
main.intervals.add(i3);
main.intervals.add(i4);
Interval winningInterval = main.processIntervals(main.intervals);
System.out.println("winning interval="+winningInterval);
}
public Interval processIntervals(ArrayList<Interval> intervals)
{
SortedSet<Integer> intervalEdges = new TreeSet<Integer>();
for(int i = 0;i<intervals.size();i++)
{
Interval currentInterval = intervals.get(i);
intervalEdges.add(currentInterval.a);
intervalEdges.add(currentInterval.b);
}
System.out.println(intervalEdges);
//edges stores the same data as intervalEdges, but for convenience, it is a list
ArrayList<Integer> edges = new ArrayList<Integer>(intervalEdges);
ArrayList<Interval> intersectionIntervals = new ArrayList<Interval>();
for(int i=0; i<edges.size()-1;i++)
{
Interval newInterval = new Interval(edges.get(i), edges.get(i+1), 0);
int score = 0; //the sum of the values of the overlapping intervals
for(int j=0; j<intervals.size();j++)
{
if(newInterval.isIncludedInInterval(intervals.get(j)))
score = score+ intervals.get(j).val;
}
newInterval.val = score;
intersectionIntervals.add(newInterval);
}
System.out.println(intersectionIntervals);
int maxValue=0; //the maximum value of an interval
Interval x = new Interval(-1,-1,0);//that interval with the maximum value
for(int i=0; i<intersectionIntervals.size();i++)
{
if(intersectionIntervals.get(i).val > maxValue)
{
maxValue=intersectionIntervals.get(i).val;
x=intersectionIntervals.get(i);
}
}
return x;
}
}
class Interval
{
public int a, b, val;
public Interval(int a, int b, int val) {
super();
this.a = a;
this.b = b;
this.val = val;
}
#Override
public String toString() {
return "Interval [a=" + a + ", b=" + b + ", val=" + val + "]";
}
boolean isIncludedInInterval(Interval y)
{
//returns true if current interval is included in interval y
return this.a>=y.a && this.b<= y.b;
}
}
gives the output
[0, 10, 20, 30, 40, 50, 60, 70]
[Interval [a=0, b=10, val=1], Interval [a=10, b=20, val=2], Interval [a=20, b=30, val=3], Interval [a=30, b=40, val=2], Interval [a=40, b=50, val=1], Interval [a=50, b=60, val=2], Interval [a=60, b=70, val=1]]
winning interval=Interval [a=20, b=30, val=3]
This solves the case when the intervals are straight line intervals, and not angular intervals. I will come back with modifications to take into account the fact that x=x+360.

proper way to store large numbers in a variable

I would like to play around with numbers and however elementary, Ive been writing algorithms for the fibonacci sequence and a brute force path for finding prime numbers!
Im not a programmer, just a math guy.
However, a problem I run into quiet often is that a long long, double and floats often run out of room.
If I wanted to continue to work in JAVA, in what way can I create my own data type so that I dont run out of room.
Conceptually, I thought to put 3 doubles together like so,
public class run {
static double a = 0;
static double b = 0;
//static double c = 0;
static void bignumber(boolean x) {
if (x == true && a < 999999999) {
++a;
} else if (x == true && a == 999999999) {
++b;
a = 0;
}
System.out.print(b + "." + a + " \n");
}
public static void main(String[] args) {
while(true) {
bignumber(true);
}
}
}
is there a better way to do this,
I would like to one day be able to say
mydataType X = 18476997032117414743068356202001644030185493386634
10171471785774910651696711161249859337684305435744
58561606154457179405222971773252466096064694607124
96237204420222697567566873784275623895087646784409
33285157496578843415088475528298186726451339863364
93190808467199043187438128336350279547028265329780
29349161558118810498449083195450098483937752272570
52578591944993870073695755688436933812779613089230
39256969525326162082367649031603655137144791393234
7169566988069
or any other number found on this site
I have also tried
package main;
import java.math.BigInteger;
public class run {
BigDecimal a = 184769970321174147430683562020019566988069;
public static void main(String[] args) {
}
}
But it still seems to be out of range
Use BigDecimal (instead of double), and BigInteger (instead of int, long) for that purpose, But you can only work with them by their methods. No operators, can be used.
Used like this:
BigInteger big = new BigInteger("4019832895734985478385764387592") // Strings...
big.add(new BigInteger("452872468924972568924762458767527");
Same with BigDecimal
BigDecimal is the class used in java where you need to represent very large or very small numbers, and maintain precision. The drawbacks are that it is not a primitive, so you can't use the normal math operators (+/-/*/etc), and that it can be a little processor/memory intensive.
You can store large numbers like this:
length
digits[]
and implement your math for them. This is not very complicated. As a hint, to make everything more simple you can store the digits in reverse order. This will make your math simpler to implement - you always add nr[k] with nr[k] and have room for transport for any length numbers, just remember to fill with 0 the shorter one.
In Knuth Seminumeric Algorithms book you can find a very nice implementation for all operations.

Categories

Resources