Coin Exchange in java Code stackOverflowError - java

cannot find the problem, everytime when I'm running this code it goes stackoverflow due to this line
countCombine += count(array,money - (array[i]*(int)(money/array[i])));
basically problem is very easy.
Given a value N, if we want to make change for N cents, and we have infinite supply of each of S = { S1, S2, .. , Sm} valued coins, how many ways can we make the change? The order of coins doesn’t matter.
For example, for N = 4 and S = {1,2,3}, there are four solutions: {1,1,1,1},{1,1,2},{2,2},{1,3}. So output should be 4. For N = 10 and S = {2, 5, 3, 6}, there are five solutions: {2,2,2,2,2}, {2,2,3,3}, {2,2,6}, {2,3,5} and {5,5}. So the output should be 5.
public class CoinExchangeProblem {
int countCombine = 0;
private int count(int array[],int money){
// sort the array
// Arrays.sort(array);
// System.out.println(Arrays.toString(array));
if (money == 0) {
return 1;
} else if (money < 0) {
return 0;
}
for(int i = 0; i < array.length; i++){
countCombine += count(array,money - (array[i]*(int)(money/array[i])));
}
return countCombine;
}
public static void main(String[] args) {
CoinExchangeProblem coinExch = new CoinExchangeProblem();
System.out.println(coinExch.count(new int[]{1,2,3}, 4));
// System.out.println(coinExch.count(new int[]{2, 5, 3, 6}, 10));
}
}

When this part
(array[i]*(int)(money/array[i]))
equals zero your are a victim of infinite recursion where you are calling the function with the same amount of money
You can change it to :
if(money >= array[i])
countCombine += count(array,money - (array[i]*(int)(money/array[i])));
so you will never get a zero here, but test it for more examples as i didn't test it a lot , but I think that it is logically right

Related

Pick from both sides?

The problem statement is :
Given an integer array A of size N.
You can pick B elements from either left or right end of the array A to get maximum sum.
Find and return this maximum possible sum.
NOTE: Suppose B = 4 and array A contains 10 elements then:
You can pick first four elements or can pick last four elements or can pick 1 from front and 3 from back etc . you need to return the maximum possible sum of elements you can pick.
public class Solution {
ArrayList<Integer> c = new ArrayList<>();
ArrayList<Integer> A= new ArrayList<>();
public int solve(ArrayList<Integer> A, int B) {
if (B>A.size()){
int sum=0;
for(int i=0;i<A.size();i++)
sum= sum+A.get(i);
return sum;
}
int max_sum=0;
for(int i=0;i<A.size();i++){
if((max_sum<suffix(A.size()-(B-i))+prefix(i-1)) ){
max_sum=suffix(A.size()-(B-i))+prefix(i-1);
}
}
return max_sum;
}
int prefix_sum=0;
int prefix(int a) {
for(int p=0;p<a+1;p++){
c=A;
prefix_sum=prefix_sum + c.get(p);
}
return prefix_sum;
}
int suffix_sum=0;
int suffix(int b){
c=A;
for(int q=b;q<c.size();q++){
suffix_sum=suffix_sum+c.get(q);
}
return suffix_sum;
}
}
I am getting runtime error, I have tried to implement the suffix and prefix methods which return the sum from the index[ 0, i] and sum from [i, N-i] respectively, then in the solve function I am trying to find the sum of prefix [a-1] +suffix[N-(b-a)] and find out the maximum sum, the syntax is completely correct, there is something wrong with the logic I assume, please help me find the correct solution by correcting this code instead of providing an alternative method
package com.array;
import java.util.Arrays;
import java.util.List;
public class PickFromBothSides {
public static void main(String[] args) {
Integer[] arr = { 5, -2, 3, 1, 2 };
System.out.println(solve(Arrays.asList(arr), 3));
}
public static int solve(List<Integer> A, int B) {
int n = A.size();
int result = 0;
for (int i = 0; i < B; i++) {
result += A.get(i);
}
int sum = result;
for (int i = 0; i < B; i++) {
sum -= A.get(B - 1 - i);
sum += A.get(n - 1 - i);
result = Math.max(result, sum);
}
return result;
}
}
Runtime O(n)
Space complexity O(1)
You are declaring int prefix_sum=0; and int suffix_sum=0; as fields, not as local variables of the respective methods.
You are calling suffix(A.size()-(B-i)) so with your example that is 10 - (4 -i) which is 6 + i. You iterate through i being in the range {0, ..., 10} so the value 6 + i will be all the numbers 6 through 16. You cannot index in the array above 9, so you get an exception.
You need to change
for(int i=0;i<A.size();i++){
to
for(int i=0; i <= B; i++){
because you are trying to ask each iteration "how many numbers are taken from the beginning"? 0, 1, 2, 3 or 4 if B is 4
Other upgrades:
You are calling suffix(A.size()-(B-i))+prefix(i-1)) twice in a row. Call it only once, store it in a variable and reuse.
You are calling prefix(i-1) but inside prefix() you are using the parameter a as a + 1. You don't need to subtract one and add one to the same thing

Understanding this recursion function

I am altering/improving this recursive function. My intention is to add a global class variable nrOfFails to store all the iterations where the search was unsuccessful.
I call the function as follows:
{
ArrayList<Integer> solutions = new ArrayList<>();
int[] money1= {2,2,2,5,10,10,20}
int targe1 = 24
System.out.print(solutions(money1,target1,solutions))
}
/**
* Returns the number of ways of creating specified target value as a sum of money starting with c
* #param money the set of coins
* #param c Index of the array
* #param target the amount to give back
* #return number of ways
*/
private static int solutions(int[] money, int c, int target, ArrayList<Integer> s)
{
assert money!=null : "array should be initialized";
assert c>=0&&c<=money.length;
nrOfFails = 0;
if(target==0)
{
showSolution(s);
return 1;
}
if(target<0)
return 0;
if(c>=money.length)
return 0;
else
{
s.add(money[c]);
int with = solutions(money, c + 1, target - money[c], s);
s.remove(s.size()-1);
int without = solutions(money, c + 1, target,s);
return with + without;
}
}
private static void showSolution(ArrayList<Integer> s)
{
System.out.print(s);
}
I came up with a primitive way of 'counting' the unsuccessful iterations, but I would like to use recursion to solve this problem.
As for the primitive solution. I tried to check if at any iteration the content of money[] there was a value that didn't contain a multiple of the target quantity, then we searched in vain. Using a for, and a counter to check if there was or not a common multiple, if there wasn't any then we searched in vain.
Let's consider the "iterations where the search was unsuccessful" which you wish to count.
One such case is when you pass a negative target to the recursive call (which means target - money[c] < 0 in the solutions(money, c + 1, target - money[c], s) recursive call).
Another such case is when you run out of array elements before reaching the target sum (i.e. when c >= money.length).
Therefore you should increment your nrOfFails counter in these two cases. I unified them into a single condition, to make the code shorter:
static int nrOfFails = 0;
private static int solutions(int[] money, int c, int target, ArrayList<Integer> s)
{
assert money != null : "array should be initialized";
assert c >= 0 && c <= money.length;
if (target == 0) {
showSolution(s);
return 1;
} else if (target < 0 || c >= money.length) {
nrOfFails++;
return 0;
} else {
s.add(money[c]);
int with = solutions(money, c + 1, target - money[c], s);
s.remove(s.size() - 1);
int without = solutions(money, c + 1, target, s);
return with + without;
}
}
You have to reset the static variable to 0 prior to the first call to solutions.
Note that you forgot the c argument in your initial call to the recursive method. I added it here. I also added resetting and printing of nrOfFails:
nrOfFails = 0;
ArrayList<Integer> solutions = new ArrayList<>();
int[] money1= {2,2,2,5,10,10,20};
int target = 24;
System.out.println(solutions(money1,0,target,solutions));
System.out.println ("number of fails = " + nrOfFails);
This produces the following output:
[2, 2, 10, 10]
[2, 2, 20]
[2, 2, 10, 10]
[2, 2, 20]
[2, 2, 10, 10]
[2, 2, 20]
6
number of fails = 110

Array is ignoring last index for some number of array length

import java.util.Scanner;
public class Test {
public static void display(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.printf("%d\n", arr[i]);
}
System.out.printf("\n");
}
// this one is the problematic one.
public static int min(int[] arr, int start, int end) {
int middle = start + (end - start)/2;
if (start >= middle) {
return arr[start];
}
int min_1 = min(arr, start, middle);
int min_3 = (min_1 <= arr[middle])? min_1 : arr[middle];
int min_2 = min(arr, middle+1, end);
return (min_3 <= min_2)? min_3 : min_2;
}
public static void main(String[] args) {
int len;
Scanner in = new Scanner(System.in);
System.out.printf("Enter the length of array: ");
len = in.nextInt();
int[] arr = new int[len];
for (int i = 0; i < len; i++) {
arr[i] = (int)(10*Math.random()+1);
}
arr[len-1] = 0;
display(arr);
System.out.printf("%d is the min", min(arr, 0, arr.length-1));
}
}
Problem is: the method min() works for the other places of minimum number (which is "0" in this example) for example if I put "0" in the 3rd place (by changing arr[len-1] = 0 part), method returns me 0. If I change the input length "len" to 3,7,13 or 14 it returns me 0, which is correct however for other lengths such as 4,5,8,9, it returns the second minimum number. And what is even more interesting is that if I make the end point "arr.length" instead of "arr.length-1", it won't give an error for some lengths (for instance for len = 6, it gives ArrayIndexOutOfBoundsException), moreover it works correctly and returns 0 in the situations where it doesn't give an error. I really don't understand what is the exact problem (Note: I must find the min number recursively and by finding the min of first half and second half and comparing them, so other solutions will not help me :/).
let's consider an execution passing 4, and let's say it generates arr = [6, 10, 2, 0]
The first invocation of min() will be passed 0, 3 as start,end. middle will be 0 + (3 - 0) / 2 = 1
so, you'll call
min_1 = min(arr, 0, 1)
in this execution min will have middle = 0 + (1 - 0) / 2 = 0, end hence it will return arr[0], i.e. 6.
We're back in the outer min(), where min_3 is computed as the min between (6 and 10, i.e. 6. Then we compute min_2 = min(arr, 2, 3)
we're now in this inner execution of min. Here middle = 2 + (3 - 2) / 2 = 2. As middle == start, we return arr[2], i.e. 2.
We're back in the outer min, where we finally compute the min between min_3 and min_1, which is 2, and return it. Note that we never processed arr[3]
The problem here is your condition to stop the recursion. The idea here is that you want to stop recursion when you've degenerated to a case where you're looking at an interva of size 1. The condition for that should not be start >= middle, but rather start >= end.

Finding peak values from an array in a given range

The method getPeakCount takes an int array and a range (int) as an input and returns the number of integers that are greater than all the elements to either side for the given range.
For example, consider an array {1,4,2,6,4,5,10,8,7,11} and range 2. The result should be 3, as {..,4,2,6,4,5,..}, {..,4,5,10,8,7,..} and {..,8,7,11} satisfy this condition. These satisfy the condition because 6, 10 and 11 are all greater than the 2 elements to both their left and right.
Note that for the the corner elements like 1 and 11, there's no need to check the left and right side respectively.
My code is below, but it is not correct.
static int getPeakCount(int[] arr, int R) {
int result=0;
for(int i=0;i<arr.length;i++){
if(i==0){
if(arr[i]>arr[i+1]&&arr[i]>arr[i+2]){
result++;
}
} //-----> closing if(i==0) condition
else if(i==arr.length-1){
if(arr[i]>arr[i-1]&&arr[i]>arr[i-2]){
result++;
}
}
else if(i+R>arr.length){
if(arr[i]>arr[i-R] && arr[i]>arr[i-R+1]){
System.out.println(arr[i]);
result++;
}
}
else{
if(arr[i]>arr[i+1] && arr[i]>arr[i+2] && arr[i]>arr[i-R] && arr[i]>arr[i-R+1]){
System.out.println(arr[i]);
result++;
}
}
}
return result;
}
I don't know whether I'm going in the right direction or not, and for last if condition it's throwing an java.lang.ArrayIndexOutOfBoundsException.
P.S. Don't consider this code as solution to remove errors from this. This is just the attempt I tried.
I think the right idea, and devnull is right. You just need to check the center, so change the loop to start at 1 and end 1 before the end. I commented out the end conditions. I think this does what you were asking, though not 100% sure I understood what you were after.
I should add, I use variables like l (left), r (right) and c (center) for clarity. You can make this much faster if you have large arrays. There is also redundancy in that it checks conditions it should know are already false (if I find a peak, I should skip the next value, as it can't also be a peak).
public class PeakChecker {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
int[] array = new int[]{1, 4, 2, 6, 4, 5, 10, 8, 7, 11};
System.out.println(nPeaks(array, 2));
}
static int nPeaks(int[] array, int range) {
// Check for special cases
if (array == null) {
return 0;
}
int result = 0, l, r;
// Check main body
for (int i = 0; i < array.length; i++) {
boolean isPeak = true;
// Check from left to right
l = Math.max(0, i - range);
r = Math.min(array.length - 1, i + range);
for (int j = l; j <= r; j++) {
// Skip if we are on current
if (i == j) {
continue;
}
if (array[i] < array[j]) {
isPeak = false;
break;
}
}
if (isPeak) {
System.out.println("Peak at " + i + " = " + array[i]);
result++;
i += range;
}
}
return result;
}
}
The last if condition shall throw exception when i == arr.length - 2.
This is because arr[i+2] in that case is out of bounds.
If you read the ArrayIndexOutOfBoundsException stack trace, it will tell you a line of code the error happened on. Look on that line of code and you'll probably see arr[i+1] or arr[i-1] or something. Certainly, at least one access on that line will be out of bounds. That's the problem.

Heap Sort Questions

I am working on a homework problem that involves a heap sort implementation in java. Here is what I have so far
public class HeapSort {
public static void maxHeapify(int[] a, int i) {
int largest;
int l = 2*i;
int r = (2*i)+1;
if (l<=a.length-1 && a[l]>a[i]) {
largest = l;
}
else {
largest = i;
}
if (r<a.length-1 && a[r]>a[largest]) {
largest = r;
}
if (largest != i) {
int temp = a[i];
a[i] = a[largest];
a[largest] = temp;
maxHeapify(a,largest);
}
}
public static void buildMaxHeap(int[] a) {
for (int i=(a.length-1/2); i>=1; i--) {
maxHeapify(a,i);
}
}
public static void heapSort(int[] a) {
buildMaxHeap(a);
for (int i=a.length-1; i>=1; i--) {
int temp = a[0];
a[0] = a[i];
a[0] = temp;
maxHeapify(a,1);
}
}
Here is a main I put together to test (with output)
public static void main(String[] args) {
int[] tester = {3,2,9,45,7,15,21,11,36};
System.out.println(Arrays.toString(tester));
heapSort(tester);
System.out.println(Arrays.toString(tester));
}
[3, 2, 9, 45, 7, 15, 21, 11, 36]
[3, 45, 36, 21, 9, 15, 2, 11, 7]
I am not currently getting any errors but the output is just a bit off. Any help is very much appreciated. Thanks!
*Edited to add sample output
At a quick glance, I'd say you are missing a number of calls to maxHeapify(). It looks like you only maxHeapify() half of the heap (the half that ends in the rightmost branch), but not the rest. You must call maxHeapify() for all elements in a[0] to a[length/2].
You should move the recursive call to maxHeapify() out of the conditional for swapping. For the initial build of the heap, you must propagate all the way up to the root.
And you don't maxHeapify() the 'largest' element, but the one one level up the heap, so always i/2.
if (r<a.length-1 && a[r]>a[largest]) {
largest = r;
}
should be
if (r<=a.length-1 && a[r]>a[largest]) {
largest = r;
}
I believe you also have to call maxHeapify(a,0); instead of maxHeapify(a,1); in the last loop. Apart from that the -1/2 ordering issue in the comments mentioned above. That should do the job.

Categories

Resources