Counting elements in array recursively - big arrays - java

I am learning recursion and I am supposed to create a recursive method to count number of apperances of a specific number in an array, e.g.; {1,2,3,4,4,5} for number 4 should return 2. I know that recursion is not the ideal problem to solve this issue and I know that using endIndex is not ideal either, but that's just a textbook problem I can't seem to solve.
My method is not working well, since I always run out of heap when running through big arrays. How would I optimize such code? Thanks!
public static int countNumber(int[] array, int startIndex, int endIndex, int
number) {
int result = 0;
if (startIndex==endIndex) {
return result;
}
if (array[startIndex] == number ) {
result++;
}
result = result + countNumber(array,startIndex+1,endIndex,number);
return result;
}

Are you sure you run out of heap, not out of stack? Because running out of stack on a big array is something quite expected here. The depth of the recursion is always limited by the stack size.
You could split the array into two parts on each iteration and run the method recursively on both parts. That way, for n elements of the input array, the depth of recursion would be log2(n) instead of n. Something along the following lines:
if (startIndex == endIndex) {
if (array[startIndex] == number) {
return 1;
}
return 0;
}
return countNumber(array, startIndex, (startIndex + endIndex) / 2, number)
+ countNumber(array, (startIndex + endIndex) / 2 + 1, endIndex, number);
Of course, you could also just increase stack size (e.g. with -Xss10m parameter), or simply limit the size of your input array.

Related

Stackoverflow Error in Minimum Size Subarray Sum

My code is not working for s=120331635 and a very long array. Please find the array here http://www.filedropper.com/arraytnt . I receive error Exception in thread "main" java.lang.StackOverflowError at Solution.fsub(Solution.java:17) which appears multiple times.
Q. Given an array of n positive integers and a positive integer s, find the minimal length of a contiguous subarray of which the sum ≥ s. If there isn't one, return 0 instead.
Example:
Input: s = 7, nums = [2,3,1,2,4,3]
Output: 2
Explanation: the subarray [4,3] has the minimal length under the problem constraint
class Solution{
public int minSubArrayLen(int s, int[] nums) {
if(nums.length==0) return 0;
return fsub(s,nums,0,1);
}
public int fsub(int s, int[] A, int i, int f){
int n=A.length;
if(f>n) return fsub(s,A,0,f-i+1);
int sum = 0; for(int j = i;j<f;j++) {sum += A[j];}
if(sum>=s) return(f-i); // if found
else if(f-i == n) return 0; // if nothing found
return fsub(s,A,i+1,f+1);
}
}
By using recursion, on every call to the method, it uses method stack, which will take memory. So if its time complexity is O(2^n) where n is the size of the array, then its space complexity will be O(2^n) for this many methods calls. So 2^n space is crossing the given limits of memory.

Recursive divide array

I need to get a number of all possible ways to divide array into small sub-arrays. We can divide array verticaly and horizontaly. My algorithm works very good, but time complexity is too bad. Can you have a look how to improve it?
Parameters
nStart - first row of sub-array
nEnd - last row of sub-array
mStart, mEnd - are for second dimension (columns).
check() - functions checking end condition
return - numbers of different ways to divide array. We divide while function check return true.
public static long divide(int nStart, int nEnd, int mStart, int mEnd) {
long result = 0;
for(int i = 1; i < nEnd - nStart; i++) {
if(check(nStart, nStart + i, mStart, mEnd) && check(nStart + i, nEnd, mStart, mEnd))
result += divide(nStart, nStart + i, mStart, mEnd) * divide(nStart + i, nEnd, mStart, mEnd);
}
for(int i = 1; i < mEnd - mStart; i++) {
if(check(nStart, nEnd, mStart, mStart + i) && check(nStart, nEnd, mStart + i, mEnd))
result += divide(nStart, nEnd, mStart, mStart + i) * divide(nStart, nEnd, mStart + i, mEnd);
}
return (result == 0 ? 1 : result) % 1000000000;
}
Example
Input
2 2
10
01
Output 2
Input
3 2
101
010
Output 5
I think you need to know how check() function works. We stop dividing when next subarray have only ones or only zeros. Here is code:
public static boolean check(int nStart, int nEnd, int mStart, int mEnd) {
if((nEnd - nStart) + (mEnd - mStart) == 2)
return false;
for(int i = mStart; i < mEnd; i++) {
for(int j = nStart; j < nEnd; j++) {
if(bar[i][j] != bar[mStart][nStart])
return true;
}
}
return false;
}
By looking at your code I can see that in each step of the recursion you divide your two-dimensional array into two arrays with a single horizontal or vertical cut. Then you verify that both of these parts fulfil some condition of yours defined by the check-method and, if so, then you put these two parts into a recursion. When the recursion can no longer be continued, you return 1. Below I assume that your algorithm always produces the result you want.
I'm afraid that an effective optimization of this algorithm is highly dependent on what the check-condition does. In the trivial case it would always retuns true, when the problem collapsed into a straightforward mathematical problem that propably has a general non-recursive solution. A bit more complex, but still effectively solvable would be a scenario where the condition would only check the shape of the array, meaning that e.g. check(1,5,1,4) would return the same result as check(3,7,5,8).
The most complex is of course a general solution, where the check-condition can be anything. In this case there is not much that can be done to optimize your brute force solution, but one thing that comes to my mind is adding a memory to you algorithm. You could use the java.awt.Rectangle class (or create your own class) that would hold the dimensions of a sub-array and then have a java.util.HashMap to store the results of the executions of the divide-method for furure reference, if the method is called again with the same parameters. This would prevent duplicate work that will propaply occur.
So you define the haspmap as a static variable in you class:
static HashMap<Rectangle,Long> map = new HashMap<Rectangle,Long>();
then in the beginning of the divide-method you add the following code:
Rectangle r = new Rectangle(nStart,mStart,nEnd,mEnd);
Long storedRes = map.get(r);
if (storedRes != null) {
return storedRes;
}
and then you change the ending of the method into form:
result = (result == 0 ? 1 : result) % 1000000000;
map.put(r, result);
return result;
This should give a performance-boost for your algorithm.
To return to my earlier tought, if the check-condition is simple enough, this same optimization can be done even more effectively. For example, if your check-condition only checks the shape of the array, you will only need to have its width and height as a key to the map, which will decrease the size of the map and multiple the number of positive hits in it.

Finding product of odds in an array recursively

This is the original problem:
Write a recursive, int valued method named productOfOdds that accepts an integer array and the number of elements in the array, and returns the product of the odd-valued elements of the array. You may assume the array has at least one odd-valued element. The product of the odd-valued elements of an integer-valued array recursively may be calculated as follows:
If the array has a single element and it is odd, return the value of that element; otherwise return 1.
Otherwise, if the first element of the array is odd, return the product of that element and the result of finding the product of the odd elements of the rest of the array; if the first element is NOT odd, simply return the result of finding the product of the odd elements of the rest of the array.
This is what I have and I can't figure out why it's not working:
public static int productOfOdds(int[] arr, int index)
{
if (index == 1)
{
if ((arr[0]%2) != 0)
return arr[0];
else
return 1;
}
else if ((arr[0] % 2) != 0)
return (arr[0] * productOfOdds(arr, index - 1));
else
return productOfOdds(arr, index - 1);
}
The problem is that, while you pass in your index, you don't check the array value at your index, but the array value at 0. This should fix the problem:
public static int productOfOdds(int[] arr, int index){
if (index == 1)
{
if ((arr[index-1]%2) != 0)
return arr[index-1];
else
return 1;
}
else if((arr[index-1]%2) != 0 )
return (arr[index-1] * productOfOdds(arr, index-1));
else
return productOfOdds(arr, index-1);
}
I believe for this part:
else if ((arr[0] % 2) != 0)
return (arr[0] * productOfOdds(arr, index - 1));
You meant to say:
else if ((arr[index] % 2) != 0)
return (arr[index] * productOfOdds(arr, index - 1));
By using 0 here instead of index your result will always be
1 if arr[0] is even
arr[0] if it is odd
The reason it is not working is that you never calculate anything that's not the first array element. There is nothing in your recursion that causes it to go to the second element, the third and so on.
What may be confusing is the fact the parameter that expresses the length of the array is called index. But you're treating it like length. Anyway, let's see what you are doing here:
Your end condition seems good - if the length is 1, test the only element that exists, and do as the assignment text tells you to do.
But what about the recursion step?
Suppose you have two elements and the first one is odd. Your index is 2. So you call the same function with the same array and 1. This will return the value of the element in position zero. And then you multiply it by the element at position zero. If your array was 8 elements long, it would still be multiplying by the same first element, so you basically get (arr[0])length (if it's odd) or 1 (if it's not odd).
You have two ways to solve this problem.
Go with only one parameter, but against the text of the assignment
To do this, you have to check the last element of the array. So if your array length 1, you do as you did so far. But if it's greater than 1, you have to do:
if ( arr[index-1]%2 != 0 ) {
return arr[index-1]*productOfOdds(arr,index-1);
} else {
return productOfOdds(arr,index-1);
}
Go with two parameters, but follow the letter of the assignment
To do this, you have to also pass the parameter that says where the subarray starts. That is, you check the first element of the array, but tell the recursive step to check from the second element forward. Basically, you tell your method "Look at this array as if it's starting at position startIndex rather than 0".
private static int productOfOdds(int[] arr, int startIndex, int length) {
if (length == 1) {
if ((arr[startIndex]%2) != 0)
return arr[startIndex];
else
return 1;
} else if((arr[startIndex]%2) != 0 )
return (arr[startIndex] * productOfOdds(arr, startIndex + 1, length-1));
else
return productOfOdds(arr, startIndex+1, length-1));
}
public static int productOfOdds(int[] arr, int length ) {
return productOfOdds( arr, 0, length );
}
The second method with just two parameters is there in order to follow the letter of your assignment, which was to have a method that accepts an array and its length only. Internally it works with three parameters, but to the world you present a two-parameter method (note the private vs public modifiers).
Personally, I think the first method is more elegant, despite the fact that your instructor told you to use the first element.

How to Check Array for 3 Numbers that Add to a Specific value in JAVA?

Alright guys, I've been stuck on this problem for a while now and have not been able to get past it. This is for Java. I'd appreciate any help at this point. Here are the details: Please note, we must do this in O(n) running time. We are given an array of numbers and must go through it to determine if there are any 3 numbers that sum to a specific number. HOWEVER, we are allowed to reuse any number in the array up to 3 times because we need a total of 3 numbers. We also have to output which 3 numbers gave the sum. Returning true or false.
Below is what I've got:
Do you guys have any suggestions?
You can make a for loop inside of a for loop inside of a for loop. This is for school, so I wont give you the code, but I'll give you the pseudo.
Edit: missed the O(n) part, sorry. This way should work.
public static void main(String[] args)
{
int[] test = {1,8,2,3,11,4};
System.out.println(threeSumTo(test, 6));
}
//check if 3 numbs in an array add up to int x
public static boolean threeSumTo(int[] array, int x)
{
//loop through the array
for (int i = 0; i < array.length; i++) {
boolean result = twoSumTo(array, x - array[i], i);
if (result) {
return result;
}
}
return false;
}
private static boolean twoSumTo(int[] array, int x, int low) {
int high = array.length - 1;
while (low < high) {
if (array[low] + array[high] == x) {
return true;
}
if (array[low] + array[high] > x) {
high--;
} else {
low++;
}
}
return false;
}
}
This seems to be a variation of the 3SUM problem and should obey the same restrictions.
Computing the 3SUM problem in less than O(n^2) is still a unsvoled problem.
Did your teacher ask a trick question or is that some kind of competition?
This is called a 3 sum problem and solving this problem in O(N) is impossible till now. The best you can do is O(N^2).
Check this article out.

Finding the minimum of an array using recursion?

Ok, so I've been trying to wrap my head around recursion in Java and I can accomplish easy tasks such as sum, reversing etc. but I have been struggling to do this exercise:
I'm trying to find the minimum number in an array using recursion but keep getting an answer of 0.0.
My understanding for recursion is that there I need to increment one element and then provide a base case that will end the recursion. I think I'm messing up when I have to return a value and when is best to call the recursion method.
This is what I have so far:
public static double findMin(double[] numbers, int startIndex, int endIndex) {
double min;
int currentIndex = startIndex++;
if (startIndex == endIndex)
return numbers[startIndex];
else {
min = numbers[startIndex];
if (min > numbers[currentIndex]) {
min = numbers[currentIndex];
findMin(numbers, currentIndex, endIndex);
}
return min;
}
} //findMin
Here's a simplified version:
public static double min(double[] elements, int index) {
if (index == elements.length - 1) {
return elements[index];
}
double val = min(elements, index + 1);
if (elements[index] < val)
return elements[index];
else
return val;
}
Hint: You're calling findMin recursively, but then not using its return value.
What's the relationship between (1) the min of the whole array, (2) the first element, and (3) the min of everything apart from the first element?
There are a variety of problems in this code including:
You don't use the result of the recursive findMin call.
startIndex will be the same for every call to findMin, because currentIndex is being set to the value of startIndex before startIndex is incremented.
If the number at index 1 in the array is <= the number at index 0, you just return that number without even making the recursive call.
A few observations in addition to the first answer:
int currentIndex = startIndex++; - you're going to miss your first element here. In general, you don't want to modify the input to your recursive function. Work off the input and generate new values when you're ready to call the function again - i.e. 'findMin(numbers, currentIndex+1, endIndex)'

Categories