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);
}
}
Related
I'm utilizing a random method that I created, rather than the java.util.Random class. The class is called "Randomizer", here is the code within it:
public class Randomizer{
public static int nextInt(){
return (int)Math.random() * 10 + 1;
}
public static int nextInt(int min, int max){
return (int)Math.random() * (max - min + 1) + min;
}
}
This code should work just fine, but when I call it in a for loop (as seen below), it always returns the minimum value.
public class Main
{
public static void main(String[] args)
{
System.out.println("Results of Randomizer.nextInt()");
for (int i = 0; i < 10; i++)
{
System.out.println(Randomizer.nextInt());
}
int min = 5;
int max = 10;
System.out.println("\nResults of Randomizer.nextInt(5, 10)");
for (int i = 0; i < 10; i++)
{
System.out.println(Randomizer.nextInt(min, max));
}
}
}
This code returns the following:
Results of Randomizer.nextInt()
1
1
1
1
1
1
1
1
1
1
Results of Randomizer.nextInt(5, 10)
5
5
5
5
5
5
5
5
5
5
I think this error has to do with the fact that the methods within Randomizer are static, but I can't imagine how I could fix this. Any help would be greatly appreciated!
Math.random() returns a floating point number (double) in the range [0, 1). When you cast that double to an integer, it truncates to 0 every time.
To solve your problem, you need to do the casts after all of the math you are trying to do. So, it should look like this:
public class Randomizer{
public static int nextInt(){
return (int)(Math.random() * 10 + 1);
}
public static int nextInt(int min, int max){
return (int)(Math.random() * (max - min + 1) + min);
}
}
Note the extra parentheses around the expression to be cast to an integer.
I wrote a simple program to calculate the maximum number of times square root can be calculated on a number , input is an interval from num1 to num2
eg:
if the input is (1,20), answer is 2, since square root of 16 is 4 , and square root of 4 is 2 .
int max = 0;
for (int i = num1; i <= num2; i++) {
boolean loop = true;
int count = 0;
int current = i;
if (i == 1) {
count++;
} else {
while (loop) {
double squareRoot = Math.sqrt(current);
if (isCurrentNumberPerfectSquare(squareRoot)) {
count++;
current = (int) squareRoot;
} else {
loop = false;
}
}
}
if (count > max) {
max = count;
}
}
return max;
static boolean isCurrentNumberPerfectSquare(double number) {
return ((number - floor(number)) == 0);
}
I get the answer, but was wondering wether this can be improved using some mathematical way ?
Any suggestions ?
To avoid more confusion here my final answer to this topic.
A combination of both previously mentioned approaches.
What 'Parameswar' is looking for is the largest perfect square formed by the lowest base.
Step 1 -
To get that calculate the largest possible perfect square based on your num2 value.
If it is outside your range, you have no perfect square within.
Step 2 -
If it is within your range, you have to check all perfect square formed by a lower base value with a higher number of times.
Step 3 -
If you find one that is within your range, replace your result with the new result and proceed to check lower values. (go back to Step 2)
Step 4 -
Once the value you check is <= 2 you have already found the answer.
Here some sample implementation:
static class Result {
int base;
int times;
}
static boolean isCurrentNumberPerfectSquare(double number) {
return ((number - Math.floor(number)) == 0);
}
private static int perfectSquare(int base, int times) {
int value = base;
for (int i = times; i > 0; i--) {
value = (int) Math.pow(base, 2);
}
return value;
}
private static Result calculatePerfectSquare(int perfectSquare) {
Result result = new Result();
result.base = (int) Math.sqrt(perfectSquare);
result.times = 1;
while (result.base > 2 && isCurrentNumberPerfectSquare(Math.sqrt(result.base))) {
result.base = (int) Math.sqrt(result.base);
result.times += 1;
}
System.out.println(perfectSquare + " -> " + result.base + " ^ " + result.times);
return result;
}
static int maxPerfectSquares(int num1, int num2) {
int largestPerfectSqr = (int) Math.pow(Math.floor(Math.sqrt(num2)), 2);
if (largestPerfectSqr < num1) {
return 0;
}
Result result = calculatePerfectSquare(largestPerfectSqr);
int currentValue = result.base;
while (currentValue > 2) {
// check lower based values
currentValue--;
int newValue = perfectSquare(currentValue, result.times + 1);
if (newValue >= num1 && newValue < num2) {
result = calculatePerfectSquare(newValue);
currentValue = result.base;
}
}
return result.times;
}
Edit - My assumption is incorrect. Refer to the answer provided by "second".
You can remove the outer loop, num2 can be directly used to determine the number with the maximum number of recursive square roots.
requiredNumber = square(floor(sqrt(num2)));
You just need to check to see if the requiredNumber exists in the range [num1, num2] after finding it.
So the refactoring code would look something like this,
int requiredNumber = Math.pow(floor(Math.sqrt(num2)),2);
int numberOfTimes=0;
if(requiredNumber>=num1) {
if (requiredNumber == 1) {
numberOfTimes=1;
} else{
while (isCurrentNumberPerfectSquare(requiredNumber)) {
numberOfTimes++;
}
}
}
Edit 4: for a more optimal approach check my other answer.
I just leave this here if anybody wants to try to follow my thought process ;)
Edit 3:
Using prime numbers is wrong, use lowest non perfect square instead
Example [35,37]
Edit 2:
Now that I think about it there is a even better approach, especially if you assume that num1 and num2 cover a larger range.
Start with the lowest prime number 'non perfect square' and
calculate the maximum perfect square that fits into your range.
If you have found one, you are done.
If not continue with the next prime number 'non perfect square'.
As a example that works well enough for smaller ranges:
I think you can improve the outerloop. There is no need to test every number.
If you know the smallest perfect square, you can just proceed to the next perfect square in the sequence.
For example:
[16, 26]
16 -> 4 -> 2 ==> 2 perfect squares
No neeed to test 17 to 24
25 -> 5 ==> 1 perfect square
and so on ...
#Chrisvin Jem
Your assumption is not correct, see example above
Edit:
Added some code
static int countPerfectSquares(int current) {
int count = 0;
while (true) {
double squareRoot = Math.sqrt(current);
if (isCurrentNumberPerfectSquare(squareRoot)) {
count++;
current = (int) squareRoot;
} else {
return count;
}
}
}
static boolean isCurrentNumberPerfectSquare(double number) {
return ((number - Math.floor(number)) == 0);
}
static int numPerfectSquares(int num1, int num2) {
int max = 0;
if (num1 == 1) {
max = 1;
}
int sqr = Math.max(2, (int) Math.floor(Math.sqrt(num1)));
int current = (int) Math.pow(sqr, 2);
if (current < num1) {
current = (int) Math.pow(++sqr, 2);
}
while (current <= num2) {
max = Math.max(countPerfectSquares(current), max);
current = (int) Math.pow(++sqr, 2);
}
return max;
}
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;
}
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 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;
}