Finding the minimum of an array using recursion? - java

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)'

Related

Counting elements in array recursively - big arrays

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.

Finding the first,last,and middle value in an array. Return the largest one

Java newbie is here. I'm practicing the array question, and I had problem with this question: Given an array of ints of odd length, look at the first, last, and middle values in the array and return the largest. The array length will be a least 1.
I know how to find the first,last,and middle value in an array. Then I tried to use if statement to solve this question.
My code:
public int maxTriple(int[] nums) {
if(nums[0]>nums[(nums.length+1)/2-1]&&nums[0]>nums[nums.length-1]){
return nums[0];
}else if(nums[(nums.length+1)/2-1>]>nums[0]&&nums[(nums.length+1)/2-1>]>
nums[nums.length-1]){
return nums[nums.length-1];
}else{
return nums[nums.length-1];
}
}
But this code does not work at all how can I fix my code?
In second else-if you have extra ">" (maybe it is a misspelling)
And if the second condition is true you need to return nums[(nums.length+1)/2-1
So you need to fix it in this way:
public int maxTriple(int[] nums) {
if(nums[0]>nums[(nums.length+1)/2-1]&&nums[0]>nums[nums.length-1]){
return nums[0];
}else if(nums[(nums.length+1)/2-1]>nums[0]&&nums[(nums.length+1)/2-1]>nums[nums.length-1]){
return nums[(nums.length+1)/2-1];
}else{
return nums[nums.length-1];
}
}
Since you are only interest in the value, not the index, you can use
public int maxTriple(int[] nums) {
int max = Math.max(nums[0], nums[nums.length - 1]);
return Math.max(max, nums[nums.length / 2]);
}
First, to make the code more readable/understandable, you should assign the 3 values of interest to local variables, and you should add some spaces around operators.
Also, since you know the length will be odd, length / 2 is enough to find middle value:
int first = nums[0];
int middle = nums[nums.length / 2];
int last = nums[nums.length - 1];
When your if block ends with a return statement, the else becomes redundant, though that is a matter of style. In this case it makes little difference, but in more complex code it can make a big difference to the code complexity.
And of course, your main problem, as PM 77-1 pointed out.
Are you aware that you return nums[nums.length-1] twice?
The middle return statement was returning the wrong value:
if (first > middle && first > last) {
return first;
}
if (middle > first && middle > last) {
return middle;
}
return last;
You can use the ternary conditional operator to write that in a single statement:
return (first > middle && first > last ? first :
middle > first && middle > last ? middle : last);
You can use the Math.max() method to simplify it:
return Math.max(Math.max(first, middle), last);
Or you can use IntStream.max(), which is better if you have many values:
return IntStream.of(first, middle, last).max().getAsInt();
Readable more than multiple conditions :
public int maxTriple(int[] nums) {
return Math.max(Math.max(nums[0], nums[nums.length - 1]), nums[nums.length / 2]);
}

How to find the maximum value in a linked list recursively?

I need to find the maximum value in a linked list given the head of the list as a parameter recursively. I have no clue how to start the recursive part of the method. This is all I have so far.
int maxOfList(List M){
List max = M;
if(M == null)
return max;
if(M.next > max){
max = M.restOfTheInts;
return maxOfList();
}
}
In recursion, you often need an entry method and a worker method. The entry method is the special case that allows the worker method to work in all cases, and the worker does the recursion.
For example, your worker might be something like:
int maxOfList(int currentMax, List<int> listToCheck) {
// Nothing to compare? currentMax is it!
if (listToCheck == null || listToCheck.size() == 0) return currentMax;
// Compare and return.
List<int> restOfList = listToCheck.subList(1, listToCheck.size());
return maxOfList(Math.max(currentMax, listToCheck.get(0)), restOfList);
}
And then to kick that off, you need your entry method:
int maxOfList(List<int> listToCheck) {
return maxOfList(Integer.MIN_VALUE, listToCheck);
}
So, for recursion to effectively work, you need to have the whole context visible inside the function.
int maxOfList(List m) {
if(m.next == null)
return m;
int previousMax = maxOfList(m.next);
if(m > previousMax)
return m;
else
return previousMax;
}
int maxValue(List m){
return maxValue(m, Integer.MIN_VALUE);
}
int maxValue(List m, int num){
if(m.next == null){
if(m.data > num)
return num = m.data;
}
return maxValue(m.next, num);
}
This should be pretty straightforward. In order to achieve a recursive solution, think about all these steps:
What's the recursive idea? The maximum of a list {L} is the max(Li, {L} - Li), where Li is the current element;
What's the stop condition? We know that if a list is empty, the maximum could be something that any number will be greater, let's say MIN_INT;
Putting all together: So, at the end we could say that a pseudo-code would look like this:
int maxOfList(List M) {
if(M == null)
return Integer.MIN_VALUE;
int max = maxOfList(M.next);
return M.value > max ? M.value : max;
}
I am supposing that the linked list has its content in value and points to next element in next (tail pointing to null). If you find any further problems, take a look at this posts:
Finding Max value in an array using recursion
Python: Recursive function to find the largest number in the list

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.

Recursive function finding max value

I feel like I am pretty close, but my return value keeps printing out the first value in the array..
public static double mx(int[] nums, int track)
maxNow = nums[0];
if (count < [lengthofarray] - 1 && nums[track] != 0)
{
if (numbers[track] > maxval)
maxval = numbers[track];
System.out.println(maxval);
return maxval = mx(nums, track+1);
}
else
return maxval;
}
currentMax is a local variable declared inside findMax. This means that if findMax calls itself, which calls itself again, which calls itself again, so that it's now on the stack four times, there will be four different currentMax variables; each findMax has its own. Thus, if one of those findMax invocations modifies currentMax, it only modifies its own; the modification has no effect on the local currentMax variables belonging to the other invocations of findMax.
There are ways to get the method invocations to share the same currentMax (passing it as a parameter, as suggested in another answer, is a possibility), but you don't need them here. Instead, look at the problem a little differently: If you want to find the maximum of numbers[3] through numbers[10], you can call your function recursively to find the maximum of numbers[4] through numbers[10], then look at numbers[3] and compare it against the maximum you found recursively.
P.S. I do not recommend making currentMax a static field in order to get it to be shared; using a global field to hold results of recursion is usually poor programming practice, in my view. (It introduces thread-unsafety, for one thing.) There are ways to do this if done carefully, but in general I believe it should be avoided.
try to simplify the code:
public static int findMax(int[] numbers, int count){
if (count > 0) {
return Math.max(numbers[count], findMax(numbers, count-1))
}
else {
return numbers[0];
}
}
Here is how you can visualize this problem:
Your data can look like
{a, b, c, d, e}
you need to find max using
max(a, max(restOfElements))
which means you need to again use
max(a, max(b, max(restOfElements)))
.
.
.
max(a, max(b, max(c, max (d, max(e, nothing)))))
and last case can be visualized even better as
max(a, . . . . )
max(b, . . . )
max(c, . . )
max (d, . )
max(e, nothing)
So in the end you have two cases
when you are handling e, where you can't compare it with anything
when you are comparing current value with max of values after it
To handle first case you just need to return e because there is nothing else to compare it with.
To handle second case just get max value from rest of elements, compare it with your current value and return greater one.
Here is how your code can look like (hover over box to see code, but before you do it, try to implement it yourself again)
public static double findMax(double[] numbers, int count) {
if (count == numbers.length - 1)//we are handling last element
return numbers[count];
//else, we are returning greater number between current element,
//and max from rest of elements
return Math.max(numbers[count], findMax(numbers, count + 1));
}
Usage example:
double[] arr = { 1, 2, 2, 1, 4, 3 };
System.out.println(findMax(arr, 0));
Output: 4.0
As an exercise instead of dividing your problem inmax(a, max(b, max(c, max(d, max(e)))) try to create method which will do it like max(max(max(max(max(a), b), c), d), e)
Well since we're giving out answers, here's how I would do it:
max(arr[1-n]) = max(arr[1], max(arr[2-n]);
public static double findMax(final double ...arr){
return findMax(arr, 0);
}
private static double findMax(final double[] arr, final int start){
// base case, if this is the end of the array, the max of the "rest"
// is just this element
if(start == arr.length - 1)
return arr[start];
// else continue
// find the max of the rest of the array
final double nextMax = findMax(arr, start + 1);
// return this index if it's greater than the next max,
// else return the next max
return arr[start] > nextMax ? arr[start] : nextMax;
}
Here's my try at it:
public static double findMax(double[] numbers, int count, double currentMax){
if( count < numbers.length ){
if( numbers[count] > currentMax ){
currentMax = numbers[count];
}
currentMax = findMax( numbers, count+1, currentMax );
}
return currentMax;
}
What exactly is the purpose of && numbers[count] != 0? What if all your numbers are negative?
Second, try passing the currentmax as an argument, instead of initializing it inside the method. You want to keep track of your currentMax. Initializing it as a local variable would not do that, but would reset it to the first element at each call.
public static double findMax(double[] numbers, int count, double currentMax)
{
if (count < numbers.length)// && numbers[count] != 0) //While the value of count remains lower than the size of the array and the current element of the arraylist doesn't = 0, the execute the code..
{
if (numbers[count] > currentMax)
currentMax = numbers[count];
return currentMax = findMax(numbers, count+1, currentMax);
}
else return currentMax;
}

Categories