Getting the first occurrence in binary search - java

I am trying to get the first occurrence of the number 5.The answer should be 2 in this case but i am getting 3 here.
public static void main(String[] args) {
int A[] = {1, 3, 5, 5, 5, 17, 20};
int index = BinarySearch(A, 5);
System.out.println(index);
}
public static int BinarySearch(int[] A, int x) {
int low = 0;
int high = A.length - 1;
while (low <= high) {
//(low + high) / 2
int mid = low + (high-low)/2; // more optimal -> low + (high-low)/2 (avoid integer overflow)
if (x == A[mid]) {
return mid;
} else if (x < A[mid]) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return -1;
}

When you find the value you are looking for, you return the mid index immediately without checking if there are smaller indices having the same value.
You have to continue searching :
public static int BinarySearch(int[] A, int x) {
int low = 0;
int high = A.length - 1;
int mid = -1;
while (low <= high) {
mid = low + (high-low)/2;
if (x <= A[mid]) { // this ensures you keep searching for the first index having
// the number you are looking for
//
// changing x <= A[mid] to x < A[mid] will give you the
// last index having the number you are looking for instead
high = mid - 1;
} else {
low = mid + 1;
}
}
if (mid >= 0 && x == A[mid]) {
return mid;
}
return -1;
}

Related

I'm getting the error ArrayIndexOutOfBoundsException: index -25 out of bonds for length 16

This is my current code for a program to find the maximum subarray. I am getting the out of bounds error for 3 lines: I'm getting the error ArrayIndexOutOfBoundsException: index -25 out of bonds for length 16. I'm testing it with the array int[]{13,-3,-25,-20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7}. I've only seen this error when using the wrong numbers for iterating through arrays in for loops, so I'm not sure what is causing it here.
static int findHigh(int[] arr) {
int high = arr[0];
for(int i = 0; i < arr.length; i++) {
if(arr[i] >= high)
high = arr[i];
}
return high;
}
static int findLow(int[] arr) {
int low = arr[0];
for(int i = 0; i < arr.length; i++) {
if(arr[i] <= low)
low = arr[i];
}
return low;
}
static Triple<Integer,Integer,Integer> findMaxSubarray(int[] arr, int low, int high){
if(high == low)
return (new Triple<> (low, high, arr[low])); //error here
else {
int mid = low + (high - low) / 2;
Triple<Integer,Integer,Integer> l = findMaxSubarray(arr, low, mid); //error here
Triple<Integer,Integer,Integer> r = findMaxSubarray(arr, mid + 1, high);
Triple<Integer, Integer, Integer> c = findMaxCrossingArray(arr, low, mid, high);
if(l.getLast() >= r.getLast() && l.getLast() >= c.getLast())
return (new Triple<> (l.getFirst(), l.getMiddle(), l.getLast()));
else if(r.getLast() >= l.getLast() && r.getLast() >= c.getLast())
return (new Triple<> (r.getFirst(), r.getMiddle(), r.getLast()));
else
return (new Triple<> (c.getFirst(), c.getMiddle(), c.getLast()));
}
}
static Triple<Integer,Integer,Integer> findMaxCrossingArray(int arr[], int low, int mid, int high){
int leftSum = Integer.MIN_VALUE, leftMax = 0;
int rightSum = Integer.MIN_VALUE, rightMax = 0;
int sum = 0;
for(int i = mid; i >= low; i--) {
sum += arr[i];
if (sum > leftSum) {
leftSum = sum;
leftMax = i;
}
}
sum = 0;
for(int j = mid; j <= high; j++) {
sum += arr[j];
if (sum > rightSum) {
rightSum = sum;
rightMax = j;
}
}
return (new Triple<> (leftMax, rightMax, leftSum + rightSum));
}
public static Triple<Integer,Integer,Integer> getMaxSubarray(int[] arr){
int high = findHigh(arr);
int low = findLow(arr);
return(findMaxSubarray(arr, low, high)); //error here
}
When you use
return (new Triple<> (low, high, arr[low]));
It take arr[index] in the third place, so if your lowest number is -25 it is causing bug with out of bonds, cause your index is -25.

Finding the square root of a number by using binary search

I tried using binary search to find the square root of an integer, but some how I couldn't pass a few test cases.
I was able to pass mySqrt(4) = 2, but I wasn't able to pass mySqrt(2147395599)
Any ideas on where I messed up?
public static int mySqrt(int x) {
int left = 0;
int right = x;
if(x < 2){
return x;
}
while(left < right){
int mid = left + ((right - left) / 2);
if(mid * mid == x){
return mid;
}
else if(mid * mid < x){
left = mid + 1;
}
else{
right = mid;
}
}
return left - 1;
}
Because mid * mid will overflow. You should use long to avoid the overflow. Then cast it back to int when you return the result.
Try this code
public static int mySqrt(int x) {
long left = 0;
long right = x;
if(x < 2){
return x;
}
while(left < right){
long mid = left + ((right - left) / 2);
if(mid * mid == x){
return (int)mid;
}
else if(mid * mid < x){
left = mid + 1;
}
else{
right = mid;
}
}
return (int)(left - 1);
}
Here is a version which handles doubles.
It is recursive.
It computes until a given precision is reached.
for (int i = 2; i < 10; i++) {
System.out.println("sqrt("+i+") = " + sqrt(i));
}
Prints
sqrt(2) = 1.414213562373095
sqrt(3) = 1.7320508075688772
sqrt(4) = 2.0
sqrt(5) = 2.23606797749979
sqrt(6) = 2.449489742783178
sqrt(7) = 2.6457513110645907
sqrt(8) = 2.82842712474619
sqrt(9) = 3.0
public static double sqrt(double i) {
return bsqrt(i, 0, i, 0);
}
static double prec = 10E-200;
private static double abs(double d) {
return d < 0 ? -d : d;
}
private static double bsqrt(double i, double low, double high,
double last) {
double mid = (high + low) / 2;
double d = last - mid;
if (d < 0) {
d = -d;
}
if (d < prec) {
return mid;
}
double sqr = mid * mid;
if (sqr < i) {
return bsqrt(i, mid, high, mid);
} else {
return bsqrt(i, low, mid, mid);
}
}
But a better way is to use Newton's method.
static double prec = 10E-15;
public static double newtons(double i) {
// initial guess
double x = i / 2;
double d = i;
double nx = 0;
while (abs(d) > prec) {
nx = x - (x*x - i)/(2*x);
d = nx - x;
x = nx;
}
return nx;
}
This is like a binary search
The following code computes the [integer] square root of a number. If the number is not a
perfect square (there is no integer square root) , then it returns -1. It does this by successive
guessing. If n is 100, it first guesses SO. Too high? Try something lower - halfway between 1
and SO. What is its runtime?
int sqrt(int n) {
return sqrt_helper(n, 1, n);
}
int sqrt_helper(int n, int min, int max) {
if (max < min) return -1; // no square root
int guess = (min + max) / 2ยท,
if (guess *guess == n) { // found it!
return guess;
}else if (guess * guess < n) { II too low
return sqrt_helper(n, guess + 1, max); // try higher
} else { // too high
return sqrt_helper(n, min, guess - l); //try lower
}
}
credits: cracking the coding interview

incompatible types: possible lossy conversion from long to int While using if condition [duplicate]

This question already has an answer here:
What does "possible lossy conversion" mean and how do I fix it?
(1 answer)
Closed 3 years ago.
/**
*
* #param b is an array
* #param x is the element for which I want to search the lower bound
* #param n is the length of the array
* #return high if element not found or mid - 1 if found
*/
static long searchMe(long b[], long x, long n){
long low = 0, high = n, mid=0;
while(low<=high){
mid = (low+high)/2;
if(b[mid] == x){
if(mid > 0 && b[mid-1] == x) high = mid-1;
else return mid-1;
}
else if(b[mid] < x) low = mid + 1;
else high = mid - 1;
}
// System.out.println(low + " == " + high);
return high;
}
You are using mid as an index of an array, but mid is long. The index of an array is always an int. You can try this.
static long searchMe(long b[], long x, long n) {
long low = 0, high = n;
int mid = 0; // CHANGED FROM long TO int
while (low <= high) {
mid = (int) ((low + high) / 2); // CAST to int
if (b[mid] == x) {
if (mid > 0 && b[mid - 1] == x)
high = mid - 1;
else
return mid - 1;
} else if (b[mid] < x)
low = mid + 1;
else
high = mid - 1;
}
// System.out.println(low + " == " + high);
return high;
}

Custom Binary Search Function is not Working Properly

I am creating a custom binary search function and am running into issues. I have looked through the code for a good while now, however, I cannot figure out why nothing is returning. Please let me know what you think. Thank you!
a is the array, b is the result that is returned in the end, and t is the target value. Pos is the current position and min and max are the minimum and maximum positions.
public static int binarySearch(int a[], int t){
int min = 0;
int max = a.length;
if (a[0] == t){
return 0;
}
int b = -1;
for (int pos = min; a[pos] != t;){
pos = (max - min) / 2;
if (a[pos] == t){
b = pos;
} else {
if(t > a[pos]){
min = pos + 1;
} else {
min = pos - 1;
}
}
}
return b;
}
Two small issues
pos = (max - min) / 2;
It looks like you're trying to find the average of the values, but are instead finding half the difference
Instead to find the average, use pos = (max - min) / 2 + min;
Also when moving the max down, you accidentally move the min up instead
min = pos - 1; should instead be max = pos - 1;
I see three issues with your code :
Your loop condition is not enough to determine the termination of the whole process . Your loop condition is a[pos] != t and you only increase or decrease the pos which will cause ArrayIndexOutOfBoundsExceptioneventually if the element we search can't be found inside the array.
Your if-else is not correct , cause you only update the value for the min and not the max too.
Instead of 'moving' the value pos by half each time, you just set it the average of min and max which is not correct.
Combine all the above and you will get this result :
public static int binarySearch(int a[], int t) {
int min = 0;
int max = a.length;
if (a[0] == t) {
return 0;
}
int b = -1;
for (int pos = min; a[pos] != t;) {
pos = min + (max - min) / 2;
if (pos >= a.length || pos <= 0) {
break;
}
if (a[pos] == t) {
b = pos;
} else {
if (t > a[pos]) {
min = pos + 1;
} else {
max = pos - 1;
}
}
}
return b;
}

Binary search condition [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I'm always confused about the condition of the binary search algorithm and it costs me a lot of time in programming contests. My question is when to use each of these conditions?
1. while (low < high)
2. while (high - low > 1)
3. while (low <= high)
low = the lowest value in the set of solutions.
high = the largest value in the set of solutions.
while (low < high) is used when you're searching the range [low, high). When updating high, use high = mid. When updating low, use low = mid + 1.
while (high - low > 1) is used when you're searching the range (low, high). When updating high, use high = mid. When updating low, use low = mid.
while (low <= high) is used when you're searching the range [low, high]. When updating high, use high = mid - 1. When updating low, use low = mid + 1.
Code below:
public class BinarySearch {
public static void main(String[] args) {
Integer[] nums = { 4, 9, 12, 18, 20, 26, 28, 29, 55 };
for (int i = 0; i < nums.length; ++i) {
System.out.println(binarySearch1(nums, nums[i]));
System.out.println(binarySearch2(nums, nums[i]));
System.out.println(binarySearch3(nums, nums[i]));
}
}
public static <T extends Comparable<T>> int binarySearch1(T[] array, T value) {
final int NOT_FOUND = -1;
int low = 0;
int high = array.length;
while (low < high) {
int mid = low + (high - low) / 2;
int comparison = array[mid].compareTo(value);
if (comparison == 0) {
return mid;
} else if (comparison > 0) {
high = mid;
} else {
low = mid + 1;
}
}
return NOT_FOUND;
}
public static <T extends Comparable<T>> int binarySearch2(T[] array, T value) {
final int NOT_FOUND = -1;
int low = -1;
int high = array.length;
while (high - low > 1) {
int mid = low + (high - low) / 2;
int comparison = array[mid].compareTo(value);
if (comparison == 0) {
return mid;
} else if (comparison > 0) {
high = mid;
} else {
low = mid;
}
}
return NOT_FOUND;
}
public static <T extends Comparable<T>> int binarySearch3(T[] array, T value) {
final int NOT_FOUND = -1;
int low = 0;
int high = array.length - 1;
while (low <= high) {
int mid = low + (high - low) / 2;
int comparison = array[mid].compareTo(value);
if (comparison == 0) {
return mid;
} else if (comparison > 0) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return NOT_FOUND;
}
}

Categories

Resources