Finding first and last occurrence of an element using BinarySearch - java

I can find the first occurrence efficiently but I'm having trouble finding the last occurrence. The answer I get for the last occurrence of the element is always the correct index plus one.
Here is my code:
class FirstAndLastOccurence{
public static int first(int[] arr, int n, int x){
int left = 0;
int right = n-1;
int res = -1;
while(left <= right){
int mid = left + (right-left)/2;
if(x < arr[mid])
right = mid-1;
if(x > arr[mid])
left = mid+1;
else{
res = mid;
right = mid-1;
}
}
return res;
}
public static int last(int[] arr, int n, int x){
int left = 0;
int right = n-1;
int res = -1;
while(left <= right){
int mid = left + (right-left)/2;
if(x < arr[mid])
right = mid-1;
if(x > arr[mid])
left = mid+1;
else{
res = mid;
left = mid+1;
}
}
return res;
}
public static void main(String[] args){
int[] arr = new int[]{2, 4, 10, 10, 10, 10, 56, 71, 90};
System.out.println(first(arr, arr.length, 10));
System.out.println(last(arr, arr.length, 10));
}
}
Output:
2
6
The first output is correct while my last output is wrong, as it should have been 5. The code I'm trying to follow is here (the code is not exactly the same, I'm implementing the binary search in a more familiar way to me personally).

You have added both the if statements and else statement at the last which gets executed only for the second if statement which is incorrect. Please find the below code which is working and giving the correct answer.
public static int last(int[] arr, int n, int x){
int left = 0;
int right = n-1;
int res = -1;
while(left <= right){
int mid = left + (right-left)/2;
if(x < arr[mid])
right = mid-1;
else if(x > arr[mid])
left = mid+1;
else{
res = mid;
left = mid+1;
}
}
return res;
}

Related

Why is my Binary search stuck in an endless loop?

I just had to pop in here to hopefully get a quick answer to my little problem. I'm trying to create a binary search method but ran into some problems. I created it iteratively, which my IDE(Intellij) apparently didn't like. It had me stuck in a endless loop of... well, you know the rest. Any suggestions?
Here is my simple, yet beautiful little snippet of code:
static int searchIt(int[] arr, int target){
int left = 0;
int right = arr.length - 1;
while (left <= right){
int mid = (right + left) / 2;
if(arr[mid] == target) {
return mid;
} else if(target < arr[mid]){
right = mid-1;
} else{
left = mid -1;
}
}
return -1;
}
No errors, not in runtime or compile time, just endless nothingness...
left value should be mid + 1 since if the your middle your target value greater than your mid value then you need to search the element in second half of your array
static int searchIt(int[] arr, int target){
int left = 0;
int right = arr.length - 1;
while (left <= right){
int mid = (right + left) / 2;
if(arr[mid] == target) {
return mid;
} else if(target < arr[mid]){
right = mid - 1;
} else{
left = mid + 1;
}
}
return -1;
}

Logical error in a quicksort using a median of 3

The instruction is to edit a quicksort program to select the median of three as the pivot as opposed to the first value of an array.
In order to do so, I've edited the code as follows:
public class medianOf3 {
//Main method and test array
public static void main(String[] args) {
int[] list = {2, 3, 2, 5, 6, 1, -2, 3, 14, 12};
quickSort(list);
for (int i = 0; i < list.length; i++)
System.out.print(list[i] + " ");
System.out.println();
}
public static void quickSort(int[] list) {
quickSort(list, 0, list.length - 1);
}
//The quicksort method
public static void quickSort(int[] list, int first, int last) {
if (last > first) {
int pivotIndex = partition(list, first, last);
quickSort(list, first, pivotIndex - 1);
quickSort(list, pivotIndex + 1, last);
}
}
// Returns the median of three integers
public static int median(int first, int middle, int last) {
return Math.max(Math.min(first, middle), Math.min(Math.max(first, middle), last));
}
//returns the index of a value
public static int findIndex (int[] list, int t) {
if (list == null) return -1;
int len = list.length;
int i = 0;
while (i < len) {
if (list[i] == t) return i;
else i=i+1;
}
return -1;
}
public static int partition(int[] list, int first, int last) {
int middle = ((last-first) / 2)+first;
int pivot = median(list[first], list[middle], list[last]); // selecting the median of three (of the first, middle and last value) as the pivot
int low = first +1; // Index for forward search
int high = last; // Index for backward search
int index = findIndex(list, pivot );
int swap = list[index];
list[index] = list[0];
list[0] = swap;
while (high > low) {
// Search forward from left
while (low <= high && list[low] <= pivot)
low++;
// Search backward from right
while (low <= high && list[high] > pivot)
high--;
// Swap two elements in the list
if (high > low) {
int temp = list[high];
list[high] = list[low];
list[low] = temp;
}
}
while (high > first && list[high] >= pivot)
high--;
// Swap pivot with list[high]
if (pivot > list[high]) {
list[first] = list[high];
list[high] = pivot;
return high;
} else { return first;}
}
}
The above code returns the following output:
14 1 2 2 3 3 5 6 12 14
The desired output is this:
-2 1 2 2 3 3 5 6 12 14
Using the debugger, I'm able to get within one calculation of the array being sorted correctly,
with only the last 2 values needing to be swapped:
-2 1 2 2 3 3 5 6 14 12
Within the final circulation at the
list[index] = list[0];
line of the partition method, is where the error occurs, using the debugger. I feel this is most likely a logical error but I'm uncertain of exactly what is going wrong at that point.
All feedback appreciated.
I suggest as solution (based in your code with few changes) :
public static void main(String[] args) {
List<Integer> list = Arrays.asList(2, 3, 2, 5, 6, 1, -2, 3, 14, 12);
quickSort(list, 0, list.size() - 1);
System.out.println(list);
}
private static void quickSort(List<Integer> list, int first, int last) {
if (last - first > 0) {
int pivot = pivot(list, first, last);
int index = partition(list, first, last, pivot);
quickSort(list, first, index - 1);
quickSort(list, index + 1, last);
}
}
private static int pivot(List<Integer> list, int first, int last) {
return ((last - first) / 2) + first;
}
private static int partition(List<Integer> list, int first, int last, int pivot) {
Collections.swap(list, last, pivot);
int j = first;
for (int i = first; i < last; i++) {
if (list.get(i) <= list.get(last)) {
Collections.swap(list, i, j);
j++;
}
}
Collections.swap(list, last, j);
return j;
}
Alternate example with a single function and stack overflow prevention (worst case time complexity is still O(n^2)). In this example median of 3 is performed by sorting a[lo, md, hi], where md = (lo+hi)/2, which takes 3 if/swaps.
#SuppressWarnings("empty-statement")
public static void qsort(int[] a, int lo, int hi)
{
while(lo < hi){
int md = lo+(hi-lo)/2;
int ll = lo-1;
int hh = hi+1;
int t;
if(a[lo] > a[hi]){ // median of 3
t = a[lo];
a[lo] = a[hi];
a[hi] = t;
}
if(a[lo] > a[md]){
t = a[lo];
a[lo] = a[md];
a[md] = t;
}
if(a[md] > a[hi]){
t = a[md];
a[md] = a[hi];
a[hi] = t;
}
int p = a[md];
while(true){ // partition
while(a[++ll] < p);
while(a[--hh] > p);
if(ll >= hh)
break;
t = a[ll];
a[ll] = a[hh];
a[hh] = t;
}
ll = hh++;
// recurse on smaller part, loop on larger part
if((ll - lo) <= (hi - hh)){
qsort(a, lo, ll);
lo = hh;
} else {
qsort(a, hh, hi);
hi = ll;
}
}
}

Making a binary search function

I am working on a homework task where I am supposed to make a function that will do a binary insertion sort, but my function does not seem to work properly.
Here I have tried to combine a binary search function with a insertion sort function (it is specified in the homework task that it needs to be in the form of a function: insertionSort(int[] array, int lo, int hi))
public static void insertionSort(int[] array, int lo, int hi){
int mid;
int pos;
for (int i = 1; i < array.length; i++) {
int x= array[i];
while (lo < hi) {
mid = lo + (hi -lo)/2;
if (x == array[mid]) {
pos = mid;
}
if (x > array[mid]) {
lo = mid+1;
}
else if (x < array[mid]) {
hi = mid-1;
}
}
pos = lo;
for (int j = i; j > pos; j--) {
array[j] = array[j-1];
}
array[pos] = x;
}
}
If I try to run it with the list {2,5,1,8,3}, the output will be
2 5 1 3 1 (if lo < hi and if lo > hi)
2 5 3 8 5 (if lo==hi)
What I am expecting though, is a sorted list...
Any idea of what I am doing wrong?
Just to give you a possible idea:
public static void insertionSort(int[] array) {
if (array.length <= 1) {
return;
}
// Start with an initially sorted part.
int loSorted = array.length - 1;
//int hiSorted = array.length;
while (loSorted > 0) {
// Take one from the array
int x = array[0];
// Where in the sorted part to insert?
int insertI = insertPosition(array, loSorted);
// Insert x at insertI
...
--loSorted;
}
}
whenever I need binary search, my function looks the following way:
public static void binarySearch(int arr[], int first, int last, int key){
int mid = (first + last)/2;
while( first <= last ){
if ( arr[mid] < key ){
first = mid + 1;
}else if ( arr[mid] == key ){
System.out.println("Element is found at index: " + mid);
break;
}else{
last = mid - 1;
}
mid = (first + last)/2;
}
if ( first > last ){
System.out.println("Element is not found!");
}
}
In your main method the call looks like:
public static void main(String[] args) {
int arr[] = {10,20,30,40,50};
int key = 30;
int last=arr.length-1;
binarySearch(arr,0,last,key);
}
I hope I was able to help you!
Thank you for your input. I changed the function a little bit, and it seems to be working now
` public static void insertionSort(int[] array, int lo, int hi){
int mid;
int pos;
for (int i = 1; i < array.length; i++) {
int j = i -1;
int x = array[i];
while (lo <= hi) {
mid = lo + (hi -lo)/2;
if (x == array[mid]) {
pos = mid;
break;
}
if (x > array[mid]) {
lo = mid+1;
}
else if (x < array[mid]) {
hi = mid-1;
}
}
while (j >= 0 && array[j] > x) {
array[j + 1] = array[j];
j = j - 1;
}
array[j + 1] = x;
}
}
the problem seemed to lay in the last part, where I was trying to move the elements into their right positions. The function is probably not perfect tho, so constructive criticism is welcome :)

How can i fin the index using exponential, binary or interpolatin search recursively? [duplicate]

This question already has an answer here:
How can I locate an index given the following constraints? [closed]
(1 answer)
Closed 9 years ago.
Given an array of n integers A[0…n−1], such that ∀i,0≤i≤n, we have that |A[i]−A[i+1]|≤1, and if A[0]=x, A[n−1]=y, we have that x<y. Locate the index j such that A[j]=z, for a given value of z, x≤ z ≤y
I dont understand the problem. I've been stuck on it for 4 days. Any idea of how to approach it with binary search, exponential search or interpolation search recursively? We are given an element z find the index j such that a [j] = z (a j) am i right?.
static int binarySearch(int[] searchArray, int x) {
int start, end, midPt;
start = 0;
end = searchArray.length - 1;
while (start <= end) {
midPt = (start + end) / 2;
if (searchArray[midPt] == x) {
return midPt;
} else if (searchArray[midPt] < x) {
start = midPt + 1;
} else {
end = midPt - 1;
}
}
return -1;
}
You can use the basic binary search algorithm. The fact that A[i] and A[i+1] differ by at most 1 guarantees you will find a match.
Pseudocode:
search(A, z):
start := 0
end := A.length - 1
while start < end:
x = A[start]
y = A[end]
mid := (start+end)/2
if x <= z <= A[mid]:
end := mid
else if A[mid] < z <= y
start := mid + 1
return start
Note that this doesn't necessarily return the first match, but that wasn't required.
to apply your algorithms your need a sorted array.
the condition of you problem says that you have an array which has elements that differ with max 1, not necessarily sorted!!!
so, here are the steps to write the code :
check if problem data respects given conditions
sort input array + saving old indexes values, so later can can initial positions of elements
implement you search methods in recursive way
Binary search source
Interpolation search source
Here's full example source :
public class Test {
// given start ======================================================
public int[] A = new int[] { 1, 1, 2, 3, 4, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6,
7, 8 };
public int z = 4;
// given end =======================================================
public int[] indexes = new int[A.length];
public static void main(String[] args) throws Exception {
Test test = new Test();
if (test.z < test.A[0] || test.z > test.A[test.A.length - 1]){
System.out.println("Value z="+test.z+" can't be within given array");
return;
}
sort(test.A, test.indexes);
int index = binSearch(test.A, 0, test.A.length, test.z);
if (index > -1) {
System.out.println("Binary search result index =\t"
+ test.indexes[index]);
}
index = interpolationSearch(test.A, test.z, 0, test.A.length-1);
if (index > -1) {
System.out.println("Binary search result index =\t"
+ test.indexes[index]);
}
}
public static void sort(int[] a, int[] b) {
for (int i = 0; i < a.length; i++)
b[i] = i;
boolean notSorted = true;
while (notSorted) {
notSorted = false;
for (int i = 0; i < a.length - 1; i++) {
if (a[i] > a[i + 1]) {
int aux = a[i];
a[i] = a[i + 1];
a[i + 1] = aux;
aux = b[i];
b[i] = b[i + 1];
b[i + 1] = aux;
notSorted = true;
}
}
}
}
public static int binSearch(int[] a, int imin, int imax, int key) {
// test if array is empty
if (imax < imin)
// set is empty, so return value showing not found
return -1;
else {
// calculate midpoint to cut set in half
int imid = (imin + imax) / 2;
// three-way comparison
if (a[imid] > key)
// key is in lower subset
return binSearch(a, imin, imid - 1, key);
else if (a[imid] < key)
// key is in upper subset
return binSearch(a, imid + 1, imax, key);
else
// key has been found
return imid;
}
}
public static int interpolationSearch(int[] sortedArray, int toFind, int low,
int high) {
if (sortedArray[low] == toFind)
return low;
// Returns index of toFind in sortedArray, or -1 if not found
int mid;
if (sortedArray[low] <= toFind && sortedArray[high] >= toFind) {
mid = low + ((toFind - sortedArray[low]) * (high - low))
/ (sortedArray[high] - sortedArray[low]); // out of range is
// possible here
if (sortedArray[mid] < toFind)
low = mid + 1;
else if (sortedArray[mid] > toFind)
// Repetition of the comparison code is forced by syntax
// limitations.
high = mid - 1;
else
return mid;
return interpolationSearch(sortedArray, toFind, low, high);
} else {
return -1;
}
}
}

Java BinarySearch

Can I get some help please? I have tried many methods to get this to work i got the array sorted and to print but after that my binary search function doesnt want to run and give me right results. It always gives me -1. Any help?
public class BinarySearch {
public static final int NOT_FOUND = -1;
public static int binarySearch(double[] a, double key) {
int low = 0;
int high = a.length -1;
int mid;
while (low<=high) {
mid = (low+high) /2;
if (mid > key)
high = mid -1;
else if (mid < key)
low = mid +1;
else
return mid;
}
return NOT_FOUND;
}
public static void main(String[] args) {
double key = 10.5, index;
double a[] ={10,5,4,10.5,30.5};
int i;
int l = a.length;
int j;
System.out.println("The array currently looks like");
for (i=0; i<a.length; i++)
System.out.println(a[i]);
System.out.println("The array after sorting looks like");
for (j=1; j < l; j++) {
for (i=0; i < l-j; i++) {
if (a[i] > a[i+1]) {
double temp = a[i];
a[i] = a[i+1];
a[i+1] = temp;
}
}
}
for (i=0;i < l;i++) {
System.out.println(a[i]);
}
System.out.println("Found " + key + " at " + binarySearch(double a[], key));
}
}
you are not actually comparing with the array values. in
while (low <= high) {
mid = (low + high) / 2;
if (mid > key) {
high = mid - 1;
} else if (mid < key) {
low = mid + 1;
} else {
return mid;
}
}
Instead use this section
while (low <= high) {
mid = (low + high) / 2;
if (a[mid] > key) {
high = mid - 1;
} else if (a[mid] < key) {
low = mid + 1;
} else {
return mid;
}
}
You were correct to find the indexes, but what you were doing is that you were just comparing index number with your key, which is obviously incorrect. When you write a[mid] you will actually compare your key with the number which is at index mid.
Also the last line of code is giving compile error, it should be
System.out.println("Found " + key + " at " + binarySearch(a, key));
Here
if (mid > key)
high = mid -1;
else if (mid < key)
low = mid +1;
else
return mid;
You're comparing index to a value (key) in array. You should instead compare it to a[mid]
And,
System.out.println("Found " + key + " at " + binarySearch(double a[], key));
Should be
System.out.println("Found " + key + " at " + binarySearch(a, key));
public static double binarySearch(double[] a, double key) {
if (a.length == 0) {
return -1;
}
int low = 0;
int high = a.length-1;
while(low <= high) {
int middle = (low+high) /2;
if (b> a[middle]){
low = middle +1;
} else if (b< a[middle]){
high = middle -1;
} else { // The element has been found
return a[middle];
}
}
return -1;
}
int binarySearch(int list[], int lowIndex, int highIndex, int find)
{
if (highIndex>=lowIndex)
{
int mid = lowIndex + (highIndex - lowIndex)/2;
// If the element is present at the
// middle itself
if (list[mid] == find)
return mid;
// If element is smaller than mid, then
// it can only be present in left subarray
if (list[mid] > find)
return binarySearch(list, lowIndex, mid-1, find);
// Else the element can only be present
// in right subarray
return binarySearch(list, mid+1, highIndex, find);
}
// We reach here when element is not present
// in array
return -1;
}
I somehow find the iterative version not quite easy to read, recursion makes it nice and easy :-)
public class BinarySearch {
private static int binarySearchMain(int key, int[] arr, int start, int end) {
int middle = (end-start+1)/2 + start; //get index of the middle element of a particular array portion
if (arr[middle] == key) {
return middle;
}
if (key < arr[middle] && middle > 0) {
return binarySearchMain(key, arr, start, middle-1); //recurse lower half
}
if (key > arr[middle] && middle < arr.length-1) {
return binarySearchMain(key, arr, middle+1, end); //recurse higher half
}
return Integer.MAX_VALUE;
}
public static int binarySearch(int key, int[] arr) { //entry point here
return binarySearchMain(key, arr, 0, arr.length-1);
}
}
Here is a solution without heap. The same thing can be done in an array.
If we need to find 'k' largest numbers, we take an array of size 'k' populated with first k items from the main data source. Now, keep on reading an item, and place it in the result array, if it has a place.
public static void largestkNumbers() {
int k = 4; // find 4 largest numbers
int[] arr = {4,90,7,10,-5,34,98,1,2};
int[] result = new int[k];
//initial formation of elems
for (int i = 0; i < k; ++i) {
result[i] = arr[i];
}
Arrays.sort(result);
for ( int i = k; i < arr.length; ++i ) {
int index = binarySearch(result, arr[i]);
if (index > 0) {
// insert arr[i] at result[index] and remove result[0]
insertInBetweenArray(result, index, arr[i]);
}
}
}
public static void insertInBetweenArray(int[] arr, int index, int num) {
// insert num at arr[index] and remove arr[0]
for ( int i = 0 ; i < index; ++i ) {
arr[i] = arr[i+1];
}
arr[index-1] = num;
}
public static int binarySearch(int[] arr, int num) {
int lo = 0;
int hi = arr.length - 1;
int mid = -1;
while( lo <= hi ) {
mid = (lo+hi)/2;
if ( arr[mid] > num ) {
hi = mid-1;
} else if ( arr[mid] < num ) {
lo = mid+1;
} else {
return mid;
}
}
return mid;
}
int BinSearch(int[] array, int size, int value)
{
if(size == 0) return -1;
if(array[size-1] == value) return size-1;
if(array[0] == value) return 0;
if(size % 2 == 0) {
if(array[size-1] == value) return size-1;
BinSearch(array,size-1,value);
}
else
{
if(array[size/2] == value) return (size/2);
else if(array[size/2] > value) return BinSearch(array, (size/2)+1, value);
else if(array[size/2] < value) return (size/2)+BinSearch(array+size/2, size/2, value);
}
}
or
Binary Search in Array
/**
* Find whether 67 is a prime no
* Domain consists 25 of prime numbers
* Binary Search
*/
int primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97};
int min = 0,
mid,
max = primes.length,
key = 67,
count= 0;
boolean isFound = false;
while (!isFound) {
if (count < 6) {
mid = (min + max) / 2;
if (primes[mid] == key) {
isFound = true;
System.out.println("Found prime at: " + mid);
} else if (primes[mid] < key) {
min = mid + 1;
isFound = false;
} else if (primes[mid] > key) {
max = mid - 1;
isFound = false;
}
count++;
} else {
System.out.println("No such number");
isFound = true;
}
}
/**
HOPE YOU LIKE IT
A.K.A Binary Search
Take number array of 10 elements, input a number a check whether the number
is present:
**/
package array;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;
class BinaryS
{
public static void main(String args[]) throws IOException
{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
System.out.print("Enter a number: ");
int n=Integer.parseInt(br.readLine());
int a[]={10,20,30,40,50,60,70,80,90,100};
int upper=a.length-1,lower=0,mid;
boolean found=false;
int pos=0;
while(lower<=upper)
{
mid=(upper+lower)/2;
if(n<a[mid])upper=mid-1;
else if(n>a[mid])lower=mid+1;
else
{
found=true;
pos=mid;
break;
}
}
if(found)System.out.println(n+" found at index "+pos);
else System.out.println(n+" not found in array");
}
}
Well I know I am posting this answer much later.
But according to me its always better to check boundary condition at first.
That will make your algorithm more efficient.
public static int binarySearch(int[] array, int element){
if(array == null || array.length == 0){ // validate array
return -1;
}else if(element<array[0] || element > array[array.length-1]){ // validate value our of range that to be search
return -1;
}else if(element == array[0]){ // if element present at very first element of array
return 0;
}else if(element == array[array.length-1]){ // if element present at very last element of array
return array.length-1;
}
int start = 0;
int end = array.length-1;
while (start<=end){
int midIndex = start + ((end-start)/2); // calculate midIndex
if(element < array[midIndex]){ // focus on left side of midIndex
end = midIndex-1;
}else if(element > array[midIndex]){// focus on right side of midIndex
start = midIndex+1;
}else {
return midIndex; // You are in luck :)
}
}
return -1; // better luck next time :(
}
static int binarySearchAlgorithm() {
// Array should be in sorted order. Mandatory requirement
int[] a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int lowIndex = 0;
int valueToFind = 8;
int highIndex = a.length - 1;
while (lowIndex <= highIndex) {
//Finding the midIndex;
int midIndex = (highIndex + lowIndex) / 2;
// Checking if midIndex value of array contains the value to be find.
if (a[midIndex] == valueToFind) {
return midIndex;
}
// Checking the mid Index value is less than the value to be find.
else if (a[midIndex] < valueToFind) {
// If Yes, changing the lowIndex value to midIndex value + 1;
lowIndex = midIndex + 1;
} else if (a[midIndex] > valueToFind) {
// If Yes, changing the highIndex value to midIndex value - 1;
highIndex = midIndex - 1;
} else {
return -1;
}
}
return -1;
}

Categories