This question already has answers here:
What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?
(26 answers)
Find maximum value in an array by recursion
(5 answers)
Closed 6 years ago.
when i dissect the logic of my code, it makes sense to me and looks like it should work. I need to find and return the smallest number in an array using recursion. here is my code
public static int findMin(int[] numbers, int start, int last)
{
int min = numbers[start]; // sets first value in array to minimum
if(numbers[start]<numbers[last]&& numbers[start]<min)
{ // if 1st value < last value in array and 1st value smaller than min, set min to first value
min = numbers[start];
}
else if(numbers[start]>numbers[last]&& numbers[last] < min)
{ // if 1st value > last value and last value < min, set min to last value
min = numbers[last];
}
else
{ // if 1st and last value are equal returns 1st value
return numbers[start];
}
// recursively calls... or not
findMin(numbers, start+1, last-1);
return min;
}
inputs used are 33
-55, -44, 12312, 2778, -3, -2, 53211, -1, 44, 0
output getting:
The minimum number is 0
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at Assignment9.countEven(Assignment9.java:72)
at Assignment9.countEven(Assignment9.java:87)
at Assignment9.main(Assignment9.java:34)
Expected: -55
i am assuming my recursive call is incorrectly placed. Please help, thank you.
This should do the trick
public static int findMin(int[] numbers, int start, int last)
{
if(start == last) return numbers[0];
return Math.min(numbers[start],findMin(numbers, start+1, last));
}
If for some reason you cannot use the Math.min you can always use:
public static int findMin(int[] numbers, int start, int last)
{
if(start == last) return numbers[0];
int min = findMin(numbers, start+1, last);
return (numbers[start] <= min) ? numbers[start] : min;
}
The major problems with or solution are:
-> you are not correctly checking the stop case;
-> you are not using the min value calculated in each recursive call;
-> and you are not checking for the cases that you go over the array limits.
First glance, it looks like you are not saving the result from your recursive call, you're just calling it as if it was a void method.
Instead of
findMin(numbers, start+1, last-1);
return min;
Try:
min = findMin(numbers, start+1, last-1);
return min;
Why don't you simple try this:
public static int findMin(int[] numbers, int start, int last) {
if(start == last){
return numbers[start];
}
if(numbers[start] <= numbers[last]) {
last -= 1;
} else {
start += 1;
}
return findMin(numbers, start, last);
}
OR you can use Divide and Conquer strategy as suggested by Qriss:
public static int findMin(int[] numbers){
return findMinHelper(numbers, 0, numbers.length);
}
public static int findMinHelper(int[] numbers, int left, int right){
int min1 = 0, min2 = 0;
if (left == right - 1){
return numbers[left];
} else {
min1 = findMinHelper(numbers, left, (right + left) / 2);
min2 = findMinHelper(numbers, (right + left) / 2, right);
}
return (min1 < min2) ? min1 : min2;
}
Related
I want to find a target value 4 firstly appeared place in a sequence [1, 1, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6]. when I use java.util.Arrays.binaySearch, it returns index is 9, but I expected 7.
I look java.util.Arrays.binaySearch source code
and I found some comments:
If the array contains multiple elements with the specified value, there is no guarantee which one will be found.
So how to implement a lower_bound binary search algorithm in Java, which returns the target value firstly appeared place.
Note: The lower_bound concept comes from C++, but I don't understand C++ well.
I think the implementation below will do the job correctly:
int firstOccurrence(int[] sequence, int x) {
int min = 0;
int max = sequence.length - 1;
int result = -1;
while (min <= max)
{
// find the mid value and compare it with x
int mid = min + ((max - min) / 2);
// if x is found, update result and search towards left
if (x == sequence[mid]) {
result = mid;
max = mid - 1;
} else if (x < sequence[mid]) {
// discard right half
max = mid - 1;
} else {
// discard left half
min = mid + 1;
}
}
// return the leftmost index equal to x or -1 if not found
return result;
}
Edit:
Change the way to compute mid to avoid overflow with larger sums
// Previously, can overflow since we add two integer
int mid = (min + max) / 2;
// Now
int mid = min + ((max - min) / 2);
// Another way using the unsigned right shift operator
int mid = (low + high) >>> 1;
// The left operands value (low + high) is moved right
// by the number of bits specified (2 in this case) by the right operand and
// shifted values are filled up with zeros.
// The >>> treats the value as unsigned
Building on this answer to another binary search question:
How can I simplify this working Binary Search code in C?
This is a search that is equivalent to lower_bound from C++. It returns the number of elements smaller than the value you want to find. That would be
the index of the first occurrence, or where one would be inserted if there is no occurrence:
int numSmaller(int[] seq, int valueToFind)
{
int pos=0;
int limit=seq.length;
while(pos<limit)
{
int testpos = pos+((limit-pos)>>1);
if (seq[testpos]<valueToFind)
pos=testpos+1;
else
limit=testpos;
}
return pos;
}
Note that we only need to do one comparison per iteration.
The linked answer highlights several advantages of writing a binary search this way.
It think it will help you
public static boolean binarysearch(int[] data, int target, int low, int high){
if(low>high){
System.out.println("Target not found");
return false;}
else{
int mid=(low+high)/2;
if(target==data[mid])
return true;
else if(target<data[mid])
return binarysearch(data, target, low, high);
else
return binarysearch(data, target, low, high);
}
}
The code is a simple binary search program.
I tried tracing the program but it only made me more confused. I can't figure out why the nested if has data, min, midpoint - 1, & target
vs. the bottom else if statement has data, midpoint + 1, max, target.
public static boolean binarySearch(int[] data, int min, int max, int target){
boolean found = false;
int midpoint = (min + max) / 2; // determine the midpoint
if (data[midpoint] == target)
found = true;
else if (data[midpoint] > target)
{
if (min <= midpoint - 1)
found = binarySearch(data, min, midpoint - 1, target);
}
else if (midpoint + 1 <= max)
found = binarySearch(data, midpoint + 1, max, target);
return found;
}
The array data is already sorted from smallest to largest
Therefore it finds if the value at the midpoint is greater than the target, then the target would appear in the values before midpoint. So we recursively call the method only on the left of the midpoint i.e. all the values from the min till the value before the midpoint.
Similarly if the midpoint is less than the target, the target could be found after the midpoint, therefore we recursively call the method only on the right of the midpoint i.e. all the values from the value after the midpoint to the end.
Each time time we don't include the midpoint as that is checked in the line
if (data[midpoint] == target)
e.g
Array 3 6 8 10 13 14 20. target = 14
the midpoint would be = 10 9index 4). Checking target and midpoint, we'd see that the target is greater than the midpoint and falls on the right.
So we now check for target in 13 14 20 --- from midpoint+1 (index 5) till the end.
The midpoint would be 14. And the above if statement would return true.
Binary search searches the left half (min... mid-1) and the right half (mid+1...max) recursively.
You are checking mid against target, so that is why it isn't included in that range.
You really should have a base-case for if (min >= max) return false; to prevent going out of bounds of the array.
Here is a cleaner implementation as I find it easier to understand
public static boolean binSearch(int[] data, int target) {
return _binSearch(data, target, 0, data.length);
}
private static boolean _binSearch(int[] data, int target, int low, int high) {
int mid = (low + high) / 2;
if (low >= high) return false;
if (data[mid] == target) return true;
boolean foundLeft = _binSearch(data, target, low, mid);
boolean foundRight = !foundLeft && _binSearch(data, target, mid+1, high);
return foundLeft || foundRight;
}
You divide your data into a half smaller than midpoint, with a range (min, mid-1) and bigger than midpoint, with a range (mid+1, max).
if you have an input of {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31}, and min = 0; max= 10, then
int midpoint = (0 + 10) / 2; // which is 5
Iff data[midpoint] is not what you were looking for, need need to look for everything left or right (but not midpoint itself, thats why there is a -1 and a +1 in there..)
So the range for the left half is (0, 4) and the range for the right half is (6, 10).
If you are looking for, lets say 12, we'd go left, because data[midpoint] == 13 && 13 > 12:
int midpoint = (0 + 4) / 2; // which is 2
since data[2] < 10, we'd go right, with min = 3; max = 4; and so on..
It seems the code incorrectly compares the current midpoint with the min and max index. Instead
if (min <= midpoint - 1)
:
else if (midpoint + 1 <= max)
it should use
if (min < midpoint - 1)
:
else if (midpoint + 1 < max)
Try the below attempt to correct it:
public static boolean binarySearch(int[] data, int min, int max, int target){
if (max > min) {
int midpoint = (min + max) / 2; // determine the midpoint
if (data[midpoint] == target) {
return true;
}
if (data[midpoint] > target) { // use lower half
return binarySearch(data, min, midpoint-1, target);
}
else { // use upper half
return binarySearch(data, midpoint+1, max, target);
}
}
return false;
}
See DEMO
I have a little recursive algorithm which should guess a number. I call the method guessNumber and give a number and a lower value than the number and a higher value than the number. If the value is higher than the middle of area of numbers then it makes the same process for the new area of numbers. But it the value is lower it makes the same with the lower area of numbers. And if none of these cases is true then it returns the max value (it could be the min value because they're the same at this point). But why gives that an StackOverflowError? I don't see why the programm can't end. Any help would be appreaciated. Thank you.
public class Starter {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
Starter s = new Starter();
System.out.println(s.guessNumber(18, 1, 100));
}
public int guessNumber(int num, int min, int max) {
int middle = (max - (min - 1)) / 2;
if (num > middle) {
guessNumber(num, middle + 1, max);
} else if (num < middle) {
guessNumber(num, min, middle);
}
return max;
}
}
Now I don't get an error anymore with this code:
public int guessNumber(int num, int min, int max) {
int middle = (max + min) / 2;
if (num > middle) {
return guessNumber(num, middle + 1, max);
} else if (num < middle) {
return guessNumber(num, min, middle);
}
return max;
}
But the number isn't correct. If i call it this way guessNumber(18, 1, 100) the expected output should be 18 but i get 19. And if i call it this way guessNumber(34, 1, 100) then the ouput is 37
First of all, you forgot to return the value of the recursive calls.
Second of all, your calculation of middle is wrong. For example, if min is 10 and max is 20, your calculation will assign 5 to middle, instead of 15.
public int guessNumber(int num, int min, int max) {
if (min == max) {
return min;
}
int middle = (max + min) / 2;
if (num > middle) {
return guessNumber(num, middle + 1, max);
} else {
return guessNumber(num, min, middle);
}
}
I am trying to write a function in Java that returns the greatest digit in a number using recursion.
I have managed to do it using two parameters, the number and greater digit.
Initially the greater digit parameter accepts value as 0.
static int getGreatestDigit(int num , int greater){
if(num != 0){
if(num %10 > greater){
greater = num%10;
num = num/10;
return getGreatestDigit(num , greater);
}else{
num = num/10;
return getGreatestDigit(num , greater);
}
}
return greater;
}
I want to write same recursive function but with only one parameter that is number.
Like
int getGreatestDigit(int num){
//code
}
I am stuck at logic. How to do that?
Only the first call to getGreatestDigit(num) needs to keep track of the greater result. Each recursive call to getGreatestDigit(num) will return the greatest digit in the part of the original number that it is tasked with scanning. The very first invocation of getGreatestDigit(num) can compare the number it took with the greatest number returned from all recursive calls.
int getGreatestDigit(int num)
{
if (num == 0) return 0;
int lastNum = num % 10;
int otherDigits = num / 10;
int recursiveLastNum = getGreatestDigit(otherDigits);
return Math.Max(lastNum, recursiveLastNum);
}
static int getGreatestDigit(int num)
{
return num == 0 ? 0 :
Math.Max(num % 10, getGreatestDigit(num / 10));
}
So basically, you look at the least significant digit each time, comparing it against the maximum of the rest of the digits.
You can do this, if you use the functions stack as temporary memory to hold your interim results, i.e. what was previously stored in the greater parameter.
This changes your function to be no longer tail recursive, making it worse performance wise.
int greatestDigit(int num) {
int last = num % 10;
int rest = num / 10;
if (rest == 0) {
return last;
} else {
int candidate = greatestDigit (rest);
if (candidate > last) {
return candidate;
} else {
return last;
}
}
}
/** Pseudocode:
1. if num > 9, /10 and call getGreatestDigit on that (recursive step). Then get the current digit (undivided) and return the greater of the two
2. if num <= 9, return num
*/
int getGreatestDigit(int num){
//code
}
package Map;
import java.util.ArrayList;
public class Practice8 {
public int highestDigit(int number){
ArrayList<Integer> temp= new ArrayList<>();
StringBuilder sb= new StringBuilder();
sb.append(number);
String value= sb.toString();
for(int i=0;i<value.length();i++){
temp.add((int)value.charAt(i)-'0');
}
int max=0;
for(int x: temp){
if(x>max){
max=x;
}
}
return max;
}
public static void main(String[] args) {
Practice8 practice8= new Practice8();
System.out.println(practice8.highestDigit(379));
}
}
I have a practice who's task is to find the largest digit in an integer using recursion in java. For example, for the number 13441 the digit '4' will be returned.
I have been trying for a day now and nothing worked.
What I thought could work is the following code, which I can't quite get the "base case" for:
public static int maxDigit(int n) {
int max;
if (n/100==0) {
if (n%10>(n/10)%10) {
max=n%10;
}
else
max=(n/10)%10;
}
else if (n%10>n%100)
max=n%10;
else
max=n%100;
return maxDigit(n/10);
}
As you can see it's completely wrong.
Any help would be great. Thank you
This works by recursively comparing the right most digit with the highest digit of the remaining digits (those being obtained by dividing the original number by 10):
int maxDigit(int n) {
n = Math.abs(n); // make sure n is positive
if (n > 0) {
int digit = n % 10;
int max = maxDigit(n / 10);
return Math.max(digit, max);
} else {
return 0;
}
}
The simplest base case, is that if n is 0, return 0.
public static int maxDigit(int n){
if(n==0) // Base case: if n==0, return 0
return 0;
return Math.max(n%10, maxDigit(n/10)); // Return max of current digit and
// maxDigit of the rest
}
or, slightly more concise;
public static int maxDigit(int n){
return n==0 ? 0 : Math.max(n%10, maxDigit(n/10));
}
I won't dig into your code, which I think is more complicated than it has to be. But it seems to me that the cases are actually fairly simple (unless I'm missing something):
base case: parameter only has one digit, return that one digit as parameter
general case: return whichever is higher of (the first digit in the parameter) and (the maxDigit of the remaining digits in the parameter)
You may also write:
public static int maxDigit(int n, int max){
if(n!=0) {
if(n%10 > max) {
max = n%10;
}
return maxDigit(n/10, max);
}
return max;
}
This is the solution.
public static int maxDigit(int n, int max){
if (n!=0){
if ( n%10 > max){
max = n%10;
return maxDigit(n/10,max);
}else{
return maxDigit(n/10,max);
}
}
return max;
}