Could someone help me figure out why this version of the memoized coin change doesn't work?
This is to determine the minimum number of coins to make change for a target amount.
I realize that the cache is putting in the wrong values and without using the memo cache this gives the right answer. I was also able to get a memoized version to work by not passing in the currNumCoins as an argument to the recursive calls. I'm just stumped to why this version doesn't work.
I'm initializing memo as Map<Integer, Integer> memo = new HashMap<>();
Example input: coins = [1,2,5], targetAmount = 11
Expected Answer : 3
Actual Answer: 7
class Solution {
Map<Integer, Integer> memo = new HashMap<>();
public int coinChange(int[] coins, int amount) {
return coinChangeRecHelper(coins, amount, amount, 0);
}
public int coinChangeRecHelper(int[] coins, int amount, int currAmount, int currNumCoins) {
if (currAmount < 0) {
return -1;
}
if (currAmount == 0) {
//return 0;
return currNumCoins;
}
if (memo.containsKey(currAmount)) {
return memo.get(currAmount);
}
int minCoins = Integer.MAX_VALUE;
for (int i = 0; i < coins.length; i++) {
int currCoin = coins[i];
int numCoinsTmp = coinChangeRecHelper(coins, amount, currAmount - currCoin, currNumCoins + 1);
if (numCoinsTmp != -1) {
minCoins = Math.min(minCoins, numCoinsTmp);
}
}
if (minCoins == Integer.MAX_VALUE) {
minCoins = -1;
}
memo.put(currAmount, minCoins);
return minCoins;
}
}
You need a separate memo for each recursion so one does not change the other.
For example memorizing which coins where used can be achieved like so:
import java.util.HashMap;
import java.util.Map;
public class Solution {
private Map<Integer, Integer> memo;
public int coinChange(int[] coins, int amount) {
memo = new HashMap<>();
return coinChangeRecHelper(coins, amount, amount, 0, new HashMap<Integer,Integer>());
}
public int coinChangeRecHelper(int[] coins, int amount, int currAmount, int currNumCoins, Map<Integer, Integer> coinQty ) {
if (currAmount < 0) return -1;
if (currAmount == 0) {
memo = coinQty;
return currNumCoins;
}
int minCoins = Integer.MAX_VALUE;
for (int currCoin : coins) {
Map<Integer, Integer> coinQtyCopy = new HashMap<>(coinQty);
coinQtyCopy.putIfAbsent(currCoin, 0);
coinQtyCopy.put(currCoin, coinQtyCopy.get(currCoin)+1);
int numCoinsTmp = coinChangeRecHelper(coins, amount, currAmount - currCoin, currNumCoins + 1, coinQtyCopy);
if (numCoinsTmp != -1) {
minCoins = Math.min(minCoins, numCoinsTmp);
}
}
if (minCoins == Integer.MAX_VALUE) {
minCoins = -1;
}
return minCoins;
}
public Map<Integer, Integer> getMemo() {
return memo;
}
public static void main(String[] args) {
Solution s = new Solution();
System.out.println(s.coinChange(new int[]{1,2,5}, 11) + " coins used: ");
for(int coin : s.getMemo().keySet()) {
System.out.println( s.getMemo().get(coin)+ " of " + coin);
}
}
}
The return-value of coinChangeRecHelper depends on three of its arguments (coins, currAmount, and currNumCoins), but the memo cache is keyed by only one of those values (currAmount), which inherently means that it can't accurately cache the return-value. In other words, the code implicitly assumes that coinChangeRecHelper(coins1, amount1, currAmount, currNumCoins1) == coinChangeRecHelper(coins2, amount2, currAmount, currNumCoins2), but that's a bad assumption.
I was also able to get a memoized version to work by not passing in the currNumCoins as an argument to the recursive calls.
Yes, that approach would mostly fix this issue, by eliminating a mismatched parameter that the caching doesn't account for.
The only remaining issue is coins; if your coinChange method is called twice with different sets of coins, it will erroneously retain the old cache even though it's not applicable to the new call. To fix that, I'd recommend having coinChange create the cache and pass it as an argument to coinChangeRecHelper, rather than using an instance variable.
Related
I'm doing something that produces the right result. However, it is wrong from a design POV.
The point of the program is to list the result of all the powers of a number up to and including the user-defined limit.
I have a constructor which accepts the base and the exponent from the Scanner. Then a method, which utilises a for loop to calculate the power for each exponent.
Now, the problem is that I'm printing the result from each loop iteration directly from this method. This beats the point of private variables and it being void in the 1st place.
Therefore, I want to define a getter method which returns the result of each power to the output. I used to set them just fine for if/switch statements, but I don't know how to do the same for loops. If I assign the result to a variable within the loop and return that variable from the getter then it will return only the output from the final iteration.
Private implementation
package Chapter6Review;
public class Powers {
private int target;
private int power;
public Powers(int target, int power) {
this.target = target;
this.power = power;
}
public void calculatePower() {
for (int i = 0; i <= power; i++) {
System.out.println((int) Math.pow(target, i));
}
}
/*
public int getPower() {
return
}
*/
}
User interface
package Chapter6Review;
import java.util.Scanner;
public class PowersTester {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.print("Enter your base: ");
int target = in.nextInt();
System.out.print("Enter your exponent: ");
int power = in.nextInt();
Powers tester = new Powers(target, power);
tester.calculatePower();
}
}
You can simply use a List ;
public List<Integer> calculatePower() {
int p;
List<Integer> result = new ArrayList<Integer>();
for (int i = 0; i <= power; i++) {
p = (int) Math.pow(target, i);
result.add(p);
}
return result;
}
Then in you main method, you can iterate the list to print the powers like that :
List<Integer> result = new ArrayList<Integer>();
Powers tester = new Powers(target, power);
result = tester.calculatePower();
for (int i = 0; i < result.size(); i++) {
System.out.println(result.get(i));
}
You could store each of the results in a List:
List<Power> list = new ArrayList<>();
and when you call it add it as well
list.add(new Powers(target, power));
At the end you can iterate over the list like this:
for (Power power : list){
// your code
}
You might consider using streams as well
public List<Integer> calculatePower() {
return IntStream
.rangeClosed(0, power). // iterate from 0 till power inclusive
.mapToObj(i -> (int) Math.pow(target,i))
.collect(Collectors.toList()); // get result as list
}
Thanks for all the answers. Using a list seems to be a good choice.
Since I haven't covered lists yet, I resorted to this solution for now. But I don't like having code that can affect the solution in the main. Ideally, the loop should go in the private implementation.
Main
Powers tester = new Powers(target, power);
for (int i = 0; i <= power; i++) {
tester.calculatePower(i);
System.out.println(tester.getPower());
}
Private implementation
public void calculatePower(int iPower) {
result = (int) Math.pow(target, iPower);
}
public int getPower() {
return result;
}
Question: I am trying to override the add method of ArrayList to remember the last three digits added to the arraylist. I am to then take these three values and find the maximum value among them.
It seems that I can not get my add method to save the three elements without an out of bounds error.
import java.util.ArrayList;
public class MaxThreeArrayList extends ArrayList<Integer> {
MaxThreeArrayList maxlist = new MaxThreeArrayList();
int third_last = 0;
int second_last = 0;
int last = 0;
#Override public boolean add(Integer o){
if (maxlist.size() == 1){
last = maxlist.get(maxlist.size() - 1);
}
else if (maxlist.size() == 2){
last = maxlist.get(maxlist.size() - 1);
second_last = maxlist.get(maxlist.size() - 2);
}
else if (maxlist.size() >= 3){
last = maxlist.get(maxlist.size() - 1);
second_last = maxlist.get(maxlist.size() - 2);
third_last = maxlist.get(maxlist.size() - 3);
}
return super.add(o);
}
public int getMax(){
int maximum = 0;
if (third_last >= second_last){
if (third_last >= last){
maximum = third_last;
}
}
if (second_last >= third_last){
if (second_last >= last){
maximum = second_last;
}
}
if (last >= second_last){
if (last >= third_last){
maximum = last;
}
}
return maximum;
}
public static void main(String[] args) {
}
}
I think you should separate your concerns. Your overridden add should only worry about remembering the last three things you add to the list. This can be accomplished pretty easy with a deque. The method getMax should figure out which one is the largest, as its name suggests.
public class MaxThreeArrayList extends ArrayList<Integer> {
private final Deque<Integer> deque = new LinkedList<>();
#Override public boolean add(Integer i) {
deque.addFirst(i);
if (deque.size() > 3) { deque.removeLast(); }
return super.add(i);
}
public Integer getMax() {
Integer max = 0;
for (Integer i : deque) {
if (i > max) { max = i; }
}
return max;
}
}
As an additional exercise, you may note that this code can be made more general. It doesn't need to be hard-coded to remember the last 3. You could make that number configurable.
Is there a smart way to check if all keys map to the same value? So the hash table will be as below:
a=>2;
b=>2;
c=>2;
d=>2;
So a,b,d,c and d all map to the same val. I am asking because I have to find the maximum occurrence of a number in a list but it no number is the clear max, I should just print "None". So if 2 number have the max, it means no number is the clear max in terms of occurrence. Also, how do I check if there's no clear max in the values.
Below is what I have so far but it always returns "None":
private static void getMaxOccrrance(String a) {
String[] sNew = a.split(",");
Hashtable<Integer,Integer> nums = new Hashtable<>();
for(String x : sNew) {
int num = Integer.parseInt(x);
if (!nums.containsKey(num)) {
nums.put(num, 1);
} else {
nums.put(num, nums.get(num) + 1);
}
}
int val = 0, max = 1;
for(int keys : nums.keySet()){
if(nums.get(keys) > max){
val = keys;
max = nums.get(keys);
}
}
boolean uniqueMax = true;
int count = 0;
for(int values : nums.values()){
if(val == values) {
count++;
if(count >= 2){
uniqueMax = false;
break;
}
}
}
if(uniqueMax){
System.out.println(val);
}else {
System.out.println("None");
}
}
If you work with Map in a single thread, much more efficient to keep&update this information directly on Map operations, if they are always non-decreasing by value put()s. E. g.
class MyMap<K> {
Map<K, Integer> impl;
K singleMaxKey;
int maxValue;
public void put(K key, int value) {
if (value > maxValue) {
maxValue = value;
singleMaxKey = key;
} else if (value == maxValue && !key.equals(singleMaxKey)) {
sibgleMaxKey = null;
}
impl.put(key, value);
}
}
If you have Java 8 you can do this fairly easily using streams. The following will return a map from each distinct value in a list to its frequency:
Map<Value, Integer> getFrequencyMap(Collection<Value> list) {
return list.stream().distinct()
.collect(Collectors.toMap(value -> value, value -> Collections.frequency(list, value));
}
You can call this with map.values() to get the frequency of all values in the your map.
If you wish to determine if there is more than one value that occurs the same, maximum number of times, you can check the new frequency map to see if the value occurs more than once:
Map<Key, Value> map;
Map<Value, Integer> valueFrequencies = getFrequencyMap(map.values());
int maxFrequency = valueFrequencies.values().stream().max().orElse(0);
if (Collections.frequency(valueFrequencies.values(), maxFrequency) > 1) {
// no clear max frequency
}
I have 5 lists of years and 5 lists of amounts corresponding to year lists.
year_Earnings = [2011,2012,2013];
year_Expense = [2011,2012];
year_Investment = [2013];
year_Returns=[];
year_Savings=[2011,2012,2013];
amount_Earnings = [10,20,7];
amount_Expense = [5,10];
amount_Investment = [5];
amount_Returns=[];
amount_Savings=[5,10,7];
obviously i will get ArrayIndexOutOfBoundException when i try to iterate all the lists in a single for loop. so i converted this all lists in to hash maps with key value pairs by using below code
Map<Double, Double> earningsMap = listToMap(year_Earnings, amount_Earnings);
Map<Double, Double> expensesMap = listToMap(year_Expense, amount_Expense);
Map<Double, Double> investmentMap = listToMap(year_Investment, amount_Investment);
Map<Double, Double> returnsMap = listToMap(year_Returns, amount_Returns);
Map<Double, Double> savingsMap = listToMap(year_Savings, amount_Savings);
public Map<Double, Double> listToMap(List<Double> years, List<Double> money) {
Map<Double, Double> newMap = new HashMap<Double, Double>();
if (years == null || money == null || years.size() != money.size()) {
throw new IllegalArgumentException();
}
for (int i=0; i< years.size(); i++ ) {
newMap.put(years.get(i), money.get(i));
}
return newMap;
}
now i want list like below
year_Earnings = [2011,2012,2013];
year_Expense = [2011,2012,2013];
year_Investment = [2011,2012,2013];
year_Returns=[2011,2012,2013];
year_Savings=[2011,2012,2013];
amount_Earnings = [10,20,7];
amount_Expense = [5,10,0];
amount_Investment = [0,0,5];
amount_Returns=[0,0,0];
amount_Savings=[5,10,7];
can anyone please help me in doing this stuff.. thank u in advance
I have 5 lists of years and 5 lists of amounts corresponding to year
lists.
=> This is bad solution because if you follow this then you have to manage 10 lists, Instead I would suggest you to create Only Single ArrayList<Object>, every item will be of Object type.
1) Define one class Earnings with getter/setter methods.
public class Earning {
int year;
int amount;
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
}
2) Define ArrayList<Earning> type, create object of Earnings type whenever you want and put it inside the ArrayList.
Instead of having such complicate and robust architecture i suggest you to work on it.
Enum that store the types of transaction
public enum FinancialType {
EARNING,
EXPENSE,
INVESTMENT,
RETURN,
SAVING;
}
Class that will store the
public class FinancialOperation {
private final FinancialType type;
private final int year;
private final BigDecimal value;
}
The util method that will transform then lists into structure.
private List<FinancialOperation> createFinancialOperation(FinancialType type, List<Double> years, List<Double> money) {
List<FinancialOperation> result = new ArrayList<>();
for(int i = 0; i < years.size(); i++) {
Double year = years.get(i);
Double money = moneys.get(i);
if(year == null) {
continue; //or throw
}
BigDecimal amount = BigDecimal.ZERO;
if(money != null) {
amount = new BigDecimal(money,MathContext.DECIMAL128);
}
result.add(new FinancialOperation(type,year.intValue(),amount);
}
return result;
}
The usage is quite simple to imagine.
List<FinancialOperation> earningsList = createFinancialOperation(FinancialType.EARNING,year_Earnings, amount_Earnings);
List<FinancialOperation> investmentList = createFinancialOperation(FinancialType.INVESTMENT,year_Investment, amount_Investment);
and
Map<FinancialType,List<FinancialOperation>> map = new HashMap<>();
map.put(FinancialType.EARNING,earningsList);
map.put(FinancialType.INVESTMENT,investmentList);
ArrayIndexOutOfBoundException excepts because your lists are of different size... Use the same size in all lists, and this error will dissapear...
You can do it without any additional data structure, using the following utility method:
public static int[] values(int[] arr, int[] years, int firstYear, int lastYear) {
int[] res = new int[lastYear-firstYear+1];
int arrPos = 0;
for(int i = 0; i < res.length; i++) {
int year = firstYear + i;
if (arrPos==arr.length || years[arrPos] > year)
res[i] = 0;
else
res[i] = arr[arrPos++];
}
return res;
}
The input array arr can have any number of gaps, and the output will be an array corresponding to consecutive years, from firstYear to lastYear.
It requires that you first find the minimum and maximum year value in all year arrays.
i have a task where i need to find the mode of an array. which means i am looking for the int which is most frequent. i have kinda finished that, but the task also says if there are two modes which is the same, i should return the smallest int e.g {1,1,1,2,2,2} should give 1 (like in my file which i use that array and it gives 2)
public class theMode
{
public theMode()
{
int[] testingArray = new int[] {1,1,1,2,2,2,4};
int mode=findMode(testingArray);
System.out.println(mode);
}
public int findMode(int[] testingArray)
{
int modeWeAreLookingFor = 0;
int frequencyOfMode = 0;
for (int i = 0; i < testingArray.length; i++)
{
int currentIndexOfArray = testingArray[i];
int frequencyOfEachInArray = howMany(testingArray,currentIndexOfArray);
if (frequencyOfEachInArray > frequencyOfMode)
{
modeWeAreLookingFor = currentIndexOfArray;
frequencyOfMode = modeWeAreLookingFor;
}
}
return modeWeAreLookingFor;
}
public int howMany(int[] testingArray, int c)
{
int howManyOfThisInt=0;
for(int i=0; i < testingArray.length;i++)
{
if(testingArray[i]==c){
howManyOfThisInt++;
}
}
return howManyOfThisInt;
}
public static void main(String[] args)
{
new theMode();
}
}
as you see my algorithm returns the last found mode or how i should explain it.
I'd approach it differently. Using a map you could use each unique number as the key and then the count as the value. step through the array and for each number found, check the map to see if there is a key with that value. If one is found increment its value by 1, otherwise create a new entry with the value of 1.
Then you can check the value of each map entry to see which has the highest count. If the current key has a higher count than the previous key, then it is the "current" answer. But you have the possibility of keys with similar counts so you need to store each 'winnning' answer.
One way to approach this is to check each map each entry and remove each entry that is less than the current highest count. What you will be left with is a map of all "highest counts". If you map has only one entry, then it's key is the answer, otherwise you will need to compare the set of keys to determine the lowest.
Hint: You're updating ModeWeAreLookingFor when you find a integer with a strictly higher frequency. What if you find an integer that has the same frequency as ModeWeAreLookingFor ?
Extra exercice: In the first iteration of the main loop execution, you compute the frequency of '1'. On the second iteration (and the third, and the fourth), you re-compute this value. You may save some time if you store the result of the first computation. Could be done with a Map.
Java code convention states that method names and variable name should start with a lower case character. You would have a better syntax coloring and code easier to read if you follow this convention.
this might work with a little modification.
http://www.toves.org/books/java/ch19-array/index.html#fig2
if ((count > maxCount) || (count == maxCount && nums[i] < maxValue)) {
maxValue = nums[i];
maxCount = count;
}
since it seems there are no other way, i did a hashmap after all. i am stuck once again in the logics when it comes to comparing frequencys and and the same time picking lowest integer if equal frequencys.
public void theMode()
{
for (Integer number: intAndFrequencyMap.keySet())
{
int key = number;
int value = intAndFrequencyMap.get(number);
System.out.println("the integer: " +key + " exists " + value + " time(s).");
int lowestIntegerOfArray = 0;
int highestFrequencyOfArray = 0;
int theInteger = 0;
int theModeWanted = 0;
if (value > highestFrequencyOfArray)
{
highestFrequencyOfArray = value;
theInteger = number;
}
else if (value == highestFrequencyOfArray)
{
if (number < theInteger)
{
number = theInteger;
}
else if (number > theInteger)
{
}
else if (number == theInteger)
{
number = theInteger;
}
}
}
}
Completed:
import java.util.Arrays;
public class TheMode
{
//Probably not the most effective solution, but works without hashmap
//or any sorting algorithms
public TheMode()
{
int[] testingArray = new int[] {2,3,5,4,2,3,3,3};
int mode = findMode(testingArray);
System.out.println(Arrays.toString(testingArray));
System.out.println("The lowest mode is: " + mode);
int[] test2 = new int[] {3,3,2,2,1};
int mode2=findMode(test2);
System.out.println(Arrays.toString(test2));
System.out.println("The lowest mode is: " +mode2);
int[] test3 = new int[] {4,4,5,5,1};
int mode3 = findMode(test3);
System.out.println(Arrays.toString(test3));
System.out.println(The lowest mode is: " +mode3);
}
public int findMode(int[] testingArray)
{
int modeWeAreLookingFor = 0;
int frequencyOfMode = 0;
for (int i = 0; i < testingArray.length; i++)
{
int currentIndexOfArray = testingArray[i];
int countIntegerInArray = howMany(testingArray, currentIndexOfArray);
if (countIntegerInArray == frequencyOfMode)
{
if (modeWeAreLookingFor > currentIndexOfArray)
{
modeWeAreLookingFor = currentIndexOfArray;
}
}
else if (countIntegerInArray > frequencyOfMode)
{
modeWeAreLookingFor = currentIndexOfArray;
frequencyOfMode = countIntegerInArray;
}
}
return modeWeAreLookingFor;
}
public int howMany(int[] testingArray, int c)
{
int howManyOfThisInt=0;
for(int i=0; i < testingArray.length;i++)
{
if(testingArray[i]==c){
howManyOfThisInt++;
}
}
return howManyOfThisInt;
}
public static void main(String[] args)
{
new TheMode();
}
}
Glad you managed to solve it. As you will now see, there is more than one way to approach a problem. Here's what I meant by using a map
package util;
import java.util.HashMap;
import java.util.Map;
public class MathUtil {
public static void main(String[] args) {
MathUtil app = new MathUtil();
int[] numbers = {1, 1, 1, 2, 2, 2, 3, 4};
System.out.println(app.getMode(numbers));
}
public int getMode(int[] numbers) {
int mode = 0;
Map<Integer, Integer> numberMap = getFrequencyMap(numbers);
int highestCount = 0;
for (int number : numberMap.keySet()) {
int currentCount = numberMap.get(number);
if (currentCount > highestCount) {
highestCount = currentCount;
mode = number;
} else if (currentCount == highestCount && number < mode) {
mode = number;
}
}
return mode;
}
private Map<Integer,Integer> getFrequencyMap(int[] numbers){
Map<Integer, Integer> numberMap = new HashMap<Integer, Integer>();
for (int number : numbers) {
if (numberMap.containsKey(number)) {
int count = numberMap.get(number);
count++;
numberMap.put(number, count);
} else {
numberMap.put(number, 1);
}
}
return numberMap;
}
}