Error in binary search Java - java

I've been given this binary search to figure out what's wrong with it. There is a line commented out and so far the only thing I can think of is removing that line as I don't think it is needed. Apart from that, I cannot think of anything missing - is there something really obvious that is wrong?
public boolean search(int val) {
int low = 0;
int high = size-1;
int middle = -1;
boolean found = false;
while (!found && low < high) {
middle = low + (high-low)/2;
if (a[middle] == val)
found = true;
else if (a[middle] < val)
low = middle + 1;
else // (a[middle] > val)
high = middle - 1;
}
return found;
}

Let's take the case when you have 2 values in your array: [0, 1] and you look for value 1. Let's run the code:
int low = 0;
int high = size-1; // high = 1
int middle = -1;
boolean found = false;
while (!found && low < high) {
middle = low + (high-low)/2; // middle = 0 + (1-0) / 2 = 0
if (a[middle] == val) // FALSE (because a[0] = 0)
found = true;
else if (a[middle] < val) // TRUE (because a[0] = 0 and 0 < 1)
low = middle + 1; // low = 0 + 1 = 1
else // (a[middle] > val)
high = middle - 1;
}
return found;
Because low = 1, you get out of the loop since you have a condition low < high and your return false, even though 1 is present in your array.
The problem comes from the fact that middle = low + (high-low)/2; uses int and will be rounded down.

Lets go in and make your code easier to read...
middle = low + (high-low)/2;
if (a[middle] == val) {
found = true;
break;
}
if (a[middle] < val) {
low = middle + 1;
} else {
high = middle - 1;
}
I think now it becomes clearer, what that comment is really saying - it simply expresses that this is the case when a[middle] > val.

Take the array you are search to be [1,2].
Walk the code:
Start: low = 0, high = 1.
Step1: middle = 0 - no match (1 < 2) so low = 1.
Loop check - low < high? NO - stop searching.

Related

Non-recursive binary search

I'm trying to write this bSearch() method. My professor provided some pseudocode for it; however, I'm having trouble figuring out how to implement some of it. I have coded most of it; however, I have two lines that are still not quite right. I have bolded the sections in which I am have difficulty with. Thank you!
private int bSearch(Item SearchItem)
{
int low = Integer.MIN_VALUE;
int high = Integer.MAX_VALUE;
int foundPosition = -1;
int middle;
Item midPos;
while (low <= high && **we should continue looping**)
{
middle = (low + high) / 2;
midPos = MyStore.get(middle);
if (SearchItem.equals(midPos) == true)
{
foundPosition = middle;
**quit while loop**
}
else if (SearchItem.compareTo(middle) < midPos)
{
high = middle - 1;
}
else
{
low = middle + 1;
}
}
return foundPosition;
}
Welcome to SO. You've made a decent start but here are some suggestions.
you really don't need to store foundPosition - just return the position inside the loop or -1 if the item isn't found
ideally you would be able to get the lower (generally 0) and upper range from the collection myStore. This makes more sense than using min and max integer values.
you don't need to compare booleans to true - just use the expression in your statement
compareTo returns a 0, negative or positive depending on result
That would leave you with something like the following:
private int bSearch(Item searchItem) {
int low = 0;
int high = myStore.size() - 1;
while (low <= high) {
int middle = (low + high) / 2;
int comparison = searchItem.compareTo(myStore.get(middle));
if (comparison < 0) {
low = middle + 1;
} else if (comparison > 0) {
high = middle - 1;
} else {
return middle;
}
}
return -1;
}
Note that I've changed capitalisation and formatting to something considered more standard on this site (and elsewhere).

Largest number of times square root can be calculated on numbers between 2 intervals

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;
}

Algorithms: Ruby solution timing out but Java isn't

I have the following two solutions for the following algo problem:
Suppose you have N integers from 1 to N. We define a beautiful
arrangement as an array that is constructed by these N numbers
successfully if one of the following is true for the ith position (1 <=
i <= N) in this array:
The number at the ith position is divisible by i.
i is divisible by the number at the ith position. Now given N, how many beautiful
arrangements can you construct? (N will be <= 15)
Here's the provided solution in Java:
public class Solution {
int count = 0;
public int countArrangement(int N) {
boolean[] visited = new boolean[N + 1];
calculate(N, 1, visited);
return count;
}
public void calculate(int N, int pos, boolean[] visited) {
if (pos > N)
count++;
for (int i = 1; i <= N; i++) {
if (!visited[i] && (pos % i == 0 || i % pos == 0)) {
visited[i] = true;
calculate(N, pos + 1, visited);
visited[i] = false;
}
}
}
}
And here's my Ruby solution:
def count_arrangement(n)
visited = Array.new(n + 1) # zero index left blank
count_arrangements(n, visited, 1)[:arrangements]
end
def count_arrangements(n, visited, i)
return { arrangements: 1, recursed: true } if i == n + 1 # this is end of one arrangement
max_arrangements = 0
recursed = false
1.upto(n) do |num|
next if visited[num]
if num % i == 0 || i % num == 0
recursed = true
this_visited = visited.dup
this_visited[num] = true
arrangements_obj = count_arrangements(n, this_visited, i + 1) # recursive depth only goes up to O(N)
if arrangements_obj[:recursed]
max_arrangements += arrangements_obj[:arrangements]
end
end
end
recursed ? { arrangements: max_arrangements, recursed: true } : { arrangements: -1, recursed: false }
end
Seems like the algorithmic complexity is the same (AFAIK), and yet my Ruby solution times out where the Java one doesn't. Does anyone know why this is?

I am working with the Luhn Algorithm in Java for eimacs

This is for my AP Computer Programming class and I am lost at whats wrong with my code. My other programming teacher basically sees nothing wrong with my code and I've tried various different sets of code to work, but none have. This code, however seems the most likely to work.
int[] d = {8, 7, 6, 2 };
boolean valid;
int sum = 0;
int dd;
for ( int i = 0; i < d.length; i++ )
{
if ((d[d.length - i] %10) == 0 )
{
dd = d[d.length - i] * d[d.length - 1];
sum += dd ;
}
else
{
sum += d[d.length - i] ;
}
}

if ( sum %10 == 0)
{
valid = true;
}
else
{
valid = false;
}
What am I doing wrong. Here's the error that is coming up
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 4
at TC1.work(TC1.java:24)
at TC1.main(TC1.java:12)
Here's the crux of the problem:
if ((d[d.length - i] %10) == 0 )
When i is 0, then d.length - 0 is 4. d[4] is, indeed, out of bounds.
To fix this, you can also subtract 1 from d.length, like so:
if ((d[d.length - i - 1] % 10) == 0)
When i = 0 (lowest value in for-loop), d[3] is valid
When i = 3 (highest value in for-loop), d[0] is valid
Keep in mind that d[d.length - i] appears in a few different places in your code; make sure to correct each occurence.
d[d.length - i]
At all cases when i = 0 you will get this error since arrays start at 0 and go up to array.length - 1
You can correct this by doing d[d.length - i - 1]
int[] d = {8,7,6,2 };
boolean valid;
int sum = 0;
int dd;
for ( int i = 0; i < d.length; i++ )
{
if ((d.length - i) %2 == 0 )
{
dd = d[i] * 2;
}
else
{
sum += d[i] ;
}
}

if ( sum %10 == 0)
{
valid = true;
}
else
{
valid = false;
}
Ok so I retried the code with slightly different inputs and well it worked

Count the number of occurrences of a number in a sorted array

My teacher gave me the next task:
On a sorted array, find the number of occurrences of a number.
The complexity of the algorithm must be as small as possible.
This is what I have thought of:
public static int count(int[] a, int x)
{
int low = 0, high = a.length - 1;
while( low <= high )
{
int middle = low + (high - low) / 2;
if( a[middle] > x ) {
// Continue searching the lower part of the array
high = middle - 1;
} else if( a[middle] < x ) {
// Continue searching the upper part of the array
low = middle + 1;
} else {
// We've found the array index of the value
return x + SearchLeft(arr, x, middle) + SearchRight(arr, x, middle);
}
}
return 0;
}
SearchLeft and SearchRight iterate the array, until the number doesn't show.
I'm not sure if I have achieved writing the faster code for this problem, and I would like see other opinions.
Edit: After some help from comments and answers, this is my current attempt:
public static int count(int[] array, int value)
{
return SearchRightBound(array, value) - SearchLeftBound(array, value);
}
public static int SearchLeftBound(int[] array, int value)
{
int low = 0, high = array.length - 1;
while( low < high )
{
int middle = low + (high - low) / 2;
if(array[middle] < value) {
low = middle + 1;
}
else {
high = middle;
}
}
return low;
}
public static int SearchRightBound(int[] array, int value)
{
int low = 0, high = array.length - 1;
while( low < high )
{
int middle = low + (high - low) / 2;
if(array[middle] > value) {
high = middle;
}
else {
low = middle + 1;
}
}
return low;
}
SearchLeft and SearchRight iterate the array, until the number doesn't show.
That means if the entire array is filled with the target value, your algorithm is O(n).
You can make it O(log n) worst case if you binary-search for the first and for the last occurrence of x.
// search first occurrence
int low = 0, high = a.length - 1;
while(low < high) {
int middle = low + (high-low)/2;
if (a[middle] < x) {
// the first occurrence must come after index middle, if any
low = middle+1;
} else if (a[middle] > x) {
// the first occurrence must come before index middle if at all
high = middle-1;
} else {
// found an occurrence, it may be the first or not
high = middle;
}
}
if (high < low || a[low] != x) {
// that means no occurrence
return 0;
}
// remember first occurrence
int first = low;
// search last occurrence, must be between low and a.length-1 inclusive
high = a.length - 1;
// now, we always have a[low] == x and high is the index of the last occurrence or later
while(low < high) {
// bias middle towards high now
int middle = low + (high+1-low)/2;
if (a[middle] > x) {
// the last occurrence must come before index middle
high = middle-1;
} else {
// last known occurrence
low = middle;
}
}
// high is now index of last occurrence
return (high - first + 1);
Well this is essentially binary search + walking towards the boundaries of the solution interval. The only way you could possibly speed this is up is maybe cache the last values of low and high and then use binary search to find the boarders as well, but this will really only matter for very large intervals in which case it's unlikely that you jumped right into it.

Categories