I am trying to write a method where I can find the index of the desired number using binary search and recursion only. This is the method that I wrote:
public static int binSearch_r (int[] data, int value, int from, int to)
{
if (from <= to)
{
int middle = (from+to)/2;
if (data[middle] > value)
{
binSearch_r(data, value, from, middle - 1);
}
else if (data[middle] < value)
{
binSearch_r(data, value, middle+1, to);
}
else
{
return middle;
}
}
return -1;
}
data is the original array that is inputed, value is the number I am trying to find, from is the left most index of the array and to is the right most index of the array.
The array that I tested this method with is simply {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}. However, when I set value to 9, the initial "from" to 0 and the initial "to" to array.length-1, I receive -1 instead of the desired index. This happens for any number that I set for value. What am I doing wrong?
If you are unfamiliar with recursion, this is a great resource that explains it well within a Java context.
In a recursive binary search, the recursive method will reduce the search space if it cannot find the correct index. With the reduced search space the method will call itself to find the index within this reduced space. Each recursive call expects a value to be returned.
public static int binSearch_r (int[] data, int value, int from, int to) {
if (from <= to) {
int middle = (from+to)/2;
if (data[middle] > value) {
return binSearch_r(data, value, from, middle - 1);
} else if (data[middle] < value) {
return binSearch_r(data, value, middle+1, to);
}
return middle;
}
return -1;
}
(Shifted from comment to answer question)
def bs(array,target_value,i,j):
# here i is initial postion and j is last position of array
mid=(i+j)//2
if array[mid]==target_value:
return mid
if array[mid]>target_value:
j=mid-1
return bs(array,target_value,i,j)
if array[mid]<target_value:
i=mid+1
return bs(array,target_value,i,j)
array=[1,2,3,4,5,6,7]
x=bs(array,7,0,7)
print(x)
Related
A logic question in a MOOC I'm taking asked how one would go about returning the total number of increasing subsequences within a given int array using recursion.
In my method I use an index parameter as well as a position parameter to compare values with the index. My regular base case is when the index has reached the end of the list, and then I return 1 to account for an array of length 0 to technically count as a valid increasing subsequence. The method in the else statement I currently have written is only able to find subsequences of length 2. For example, if I have array [1, 2, 3], the method only returns 7 because it isn't counting 123. I'm not sure how to write this so as to account for longer subsequences. I believe it has something to do with creating a separate array and adding values to it and then adding its length to the final value, but I'm not sure how this would be implemented recursively.
public static int bettersubseq(int[] arr, int index, int pos) {
if (index == arr.length) {
return 1;
} else {
if (pos == index) {
return 1 + bettersubseq(arr, index + 1, 0);
} else {
if (arr[pos] < arr[index] && (pos < index)) {
return 1 + bettersubseq(arr, index,pos + 1);
} else {
return 0 + bettersubseq(arr, index, pos + 1);
}
}
}
}
Let's assume I have this array: ARR = {5, 7, 3, 3, 7, 5}
and I also have the size ( = 6 in this example ) so the recursive function should return 3.
this is the declaration of the function/method:
int f(arr, size);
I tried this thing:
count = 0;
if(size == 1)
return 1;
if(x[i] != f(arr, size-1)
count++;
return count;
but it doesn't work, as f(arr, size-1) doesn't walk through all the elements of the array and compare.
hopefully you guys could help!
Here's one way to do it:
private static int f(int[] arr, int size) {
if (size <= 1) return 0; // there can't be duplicates if there are not even 2 elements!
return f(arr, size - 1) + (inArray(arr, size - 1, arr[size - 1]) ? 1 : 0);
}
private static boolean inArray(int[] arr, int size, int elem) {
if (size == 0) return false;
return arr[size - 1] == elem || inArray(arr, size - 1, elem);
}
Basically the logic is this:
The size indicates the first N elements in arr that we actually care about.
If size is less than 2, we know there can't be any duplicates, so return 0.
Now for the recursion case, we return either 1 or 0 depending on whether the last element is in the rest of the array, plus whatever number of duplicates in the rest of the array ("the last element" means array[size - 1] and "the rest" means calling the function with size - 1.)
To determine whether an element is in an array, I used a recursive method as well, with a similar idea (check if the last element is elem, then check if the rest contains elem).
I was trying out a java code to insert a new element into an array, I understand most of the program except for a line of code: "int newindex = -index-1;". Why does a negative sign used in front of the index?
Here is the full program:
public class ArrayManipulation2 {
public static void main(String[] args) {
int[] array = {6,3,5,2,-9,-5,-1,0};
Arrays.sort(array);
printArray(array);
int index= Arrays.binarySearch(array, 1);
int newindex = -index-1;
array = insertElement(array, 1, newindex);
printArray(array);
}
public static void printArray(int[] array){
for(int i=0; i<array.length; i++){
if(i!=0){
System.out.print(", ");
}
System.out.print(array[i]);
}
System.out.println();
}
public static int[] insertElement(int[] orginal, int element, int index){
int length = orginal.length;
int[] destination = new int[length+1];
System.arraycopy(orginal, 0, destination, 0, index);
destination[index]=element;
System.arraycopy(orginal, index, destination, index+1, length-index);
return destination;
}
}
I need to know why the new index is specified as "-index-1"?.
Arrays.binarySearch() returns a negative value if the item isn't already in the array, so that it can distinguish between where the item is if it is there and where it should be if it isn't there.
The code isn't correct without catering for the case where the result is positive.
Background:
The method Arrays.binarySearch() returns
the index of the search key, if it is contained in the array; otherwise, (-(insertion point) – 1). The insertion point is defined as the point at which the key would be inserted into the array: the index of the first element greater than the key, or a.length if all elements in the array are less than the specified key. Note that this guarantees that the return value will be >= 0 if and only if the key is found.
So, this API suggested be used in a sorted array, otherwise it could return unexpected return value
Then ,let me clarify the code :
If can not find the element, the method will return value "(-(insertion point) – 1)" , then get its "opposite number",so the value could be insertion+1, and then minus 1, we can get its right insert position
I am trying to find the bounds for a key within a sorted array. For example, the function takes in an array and a key, and returns the lower and upper bounds based on the contents of the array and the key given (e.g. public static int [] boundFinder).
The lower bound will be the lowest index where the key occurs, and the upper bound will be the highest index where the key occurs. Here is an example input with the proper output:
Sorted array: { 2, 3, 4, 5, 5, 5, 5, 5, 9, 9, 14, 40 }
Key: 5
Output: 3, 7
In my code, I am using binary search since the array is sorted. However, I am easily able to get the upper bound, but continuously have issues with getting the lower bound. I understand I could modify my binary search method, but have tried to use Java's Math library to get the proper min and max for my bounds. I also stored my result into an array to return back to the user.
Please let me know if my approach could be improved (code below). I was wondering if I could potentially use a different data structure or algorithm to solve this problem at an optimal speed? I understand I could always loop over the entire array but that would not be the best.
Thank you in advance!
public static int[] boundFinder(int[] array, int key) {
int [] resultArr = new int[2];
int floorIndex = -1;
int ceilingIndex = array.length;
while (floorIndex + 1 < ceilingIndex) {
resultArr[0] = Math.min(resultArr[0], binarySearch(array, floorIndex, ceilingIndex, key));
resultArr[1] = Math.max(resultArr[1], binarySearch(array, floorIndex, ceilingIndex, key));
floorIndex++;
}
return resultArr;
}
public static int binarySearch(int[] array, int floorIndex, int ceilingIndex, int key) {
while (floorIndex + 1 < ceilingIndex) {
int distance = ceilingIndex - floorIndex;
int halfDistance = distance/2;
int guessIndex = floorIndex + halfDistance;
int guessValue = array[guessIndex];
if (guessValue == key) {
return guessIndex;
} else if (guessValue > key) {
ceilingIndex = guessIndex;
} else {
floorIndex = ceilingIndex;
}
}
return 0;
}
Your logic works for upper (right) bound, because you are continuously increasing the lower start index of the array and when you reach the last index of the element where element is present, the binary search will find the element and return.
The same logic will not work for lower (left) bound because you return immediately after the finding the element. Once you reach the last index where element is present, it will always return 0 and that is what happening.
The major of disadvantage of your approach is number of binarysearch method call are equal to the number of element in the array. So the complexity of the algorithm become O(n log (n)). This is worse than O(n), which you can achieve by simple linear search.
You need to write two separate implementation for getting the left most and right most index of the element in array.
Because once you find the element in the array, you need to move either right or left to find the boundary index of the element. The logic for moving into either end boundary is different than other.
Once you find the element, check the left side of the index, if that also equal to the key, then call the search again.
public static int leftSearch(int a[], int key, int l, int h) {
if (l<=h) {
int mid = (l+h)/2;
if (a[mid] == key) {
if (mid > 0 && a[mid-1] == key) {
return leftSearch(a, key, l, mid-1);
} else {
return mid;
}
}
if (a[mid] > key) {
return leftSearch(a, key, l, mid-1);
} else {
return leftSearch(a, key, mid+1, h);
}
}
return -1;
}
Once you find the element, check the right side of the index, if that is also equal then call the search again.
public static int rightSearch(int a[], int key, int l, int h) {
if (l<=h) {
int mid = (l+h)/2;
if (a[mid] == key) {
if (mid<h && a[mid+1] == key) {
return rightSearch(a, key, mid + 1, h);
} else {
return mid;
}
}
if (a[mid] > key) {
return rightSearch(a, key, l, mid-1);
} else {
return rightSearch(a, key, mid+1, h);
}
}
return -1;
}
Main method:
public static void main(String[] args) {
int array[] = new int[]{ 2, 3, 4, 5, 5, 5, 5, 5, 9, 9, 14, 40 };
int leftIndex = leftSearch(array, 5, 0, array.length-1);
System.out.println(leftIndex);
int rightIndex = rightSearch(array, 5, 0, array.length-1);
System.out.println(rightIndex);
}
output:
3
7
I will just show you a method which clicked me:
int min=-1; int max=0;
public int[] boundFinder(int[] array,int key)
{
int[] resultArray=new int[2];
for(int i=0;i<array.length;i++)
{
if(array[i]==key)
{
max=i;
if(min==-1)//so that only lower bound is assigned to min.
{
min=i;
}
}
}
resultArray[0]=min; //stores the bounds
resultArray[1]=max;
return resultArray;
}
The value of min will be changed only once since we are using the if statement.But max will have the final or the highest bound value.Finally,I have stored these values in an array(resultArray) and returned it.
If you want to make it more simpler,you could try using array list which has some pre-defined functions to return the index.
You can customise your binary search as below to achieve your requirement ...
public static void main(String[] args){
int[] array = { 2, 3, 4, 5, 5, 5, 5, 5, 9, 9, 14, 40 };
//int[] array = { 1, 2, 5, 6, 6, 6, 6, 6, 6, 6, 6, 10 };
int key = 5;
int len = array.length;
int [] resultArr = new int[2];
resultArr[0]=0;
resultArr[1]=len-1;
while(!(array[resultArr[0]]==key && array[resultArr[1]]==key)){
int mid = (resultArr[0]+resultArr[1])/2;
if(array[mid]>key){
resultArr[1] = mid-1;
}
else if (array[mid]<key){
resultArr[0]=mid+1;
}
else{
if(array[resultArr[1]]!=key){
resultArr[1]=resultArr[1]-1;
}
else if (array[resultArr[0]]!=key)
resultArr[0]=resultArr[0]+1;
}
}
System.out.println("LowerBoundary - "+resultArr[0]+" UpperBoundary - "+resultArr[1]);
}
Rather than two separate binary search implementations, use a single binary search implementation that always finds the leftmost occurrence. Call it once with key to find the first occurrence, and then call it a second time with key+1 to find the first occurrence of a number after key. You want to subtract 1 from the result returned by the second call.
So your boundFinder method does this (assuming you're using Java's built-in binarySearch method):
int min = binarySearch(array, key);
int max = binarySearch(array, key+1) - 1;
This assumes that both key and key+1 are in the array. If you can't assume that key+1 is in the array, then you would write:
int max;
int next = binarySearch(array, key+1);
if (next < 0)
{
max = -key - 1;
}
else
{
max = key-1;
}
// fill your result array with min and max
Apologies for the ambiguous title, I could not think of something more specific.
In order to get better at solving problems recursively, I have been tackling the questions posted on CodingBat. My question is related to a variation of the following problem.
The original problem is:
Given an array of ints, compute recursively if the array contains
somewhere a value followed in the array by that value times 10. We'll
use the convention of considering only the part of the array that
begins at the given index. In this way, a recursive call can pass
index+1 to move down the array. The initial call will pass in index as
0.
array220({1, 2, 20}, 0) → true
array220({3, 30}, 0) → true
array220({3}, 0) → false
My solution to this problem is:
public boolean array220(int[] nums, int index) {
if (index >= nums.length-1) return false;
if (nums[index+1] == nums[index] * 10) return true;
return array220(nums, ++index);
}
However, in order to challenge myself, I was wondering how I would go about solving the following variation of this problem that I conceived:
Given an array of ints, compute recursively if the array contains
somewhere a value that is 10 times larger than any other value. We'll use
the convention of considering only the part of the array that begins
at the given index. In this way, a recursive call can pass index+1 to
move down the array. The initial call will pass in index as 0.
For example:
array220({1, 2, 10}, 0) → true
array220({3, 2, 9, 38, 20}, 0) → true
array220({3}, 0) → false
So basically, the difference with the original problem is that the values may not necessarily be adjacent to one another (see examples above).
How would I go about doing this recursively? I would appreciate some pointers.
I do not want to change the method signature or use global variables.
This can be the answer, just making use of a HashSet, and passing it along when you make recursive call:
public boolean array220(int[] nums,HashSet<Integer> set, int index) {
if (index >= nums.length-1) return false;
if (set.contains(nums[index]*10))
return true;
set.add(nums[index]);
return array220(nums,set, ++index);
}
If you don't want to use additional data structures, sorting array and making use of binary search can bring you an O(nlogn) solution, with two recursive methods.
Arrays.sort(nums);
public boolean array220(int[] nums, int index) {
if (index >= nums.length-1) return false;
if (binarySearch(index + 1, nums.length - 1,nums[index]*10,nums))
return true;
return array220(nums, ++index);
}
public boolean binarySearch(int start, int end,int value, int[] nums){
if(start > end)
return false;
int mid = (start + end)/2;
if(nums[mid] == value){
return true;
}else if(nums[mid] > value){
return binarySearch(start, mid - 1, value, nums);
}else{
return binarySearch(mid + 1, end, value, nums);
}
}
If you don't want to sort the array, using a linear recursive search will give a O(n^2) solution.
public boolean array220(int[] nums, int index) {
if (index >= nums.length-1) return false;
if (linearSearch(0,nums[index]*10,nums))
return true;
return array220(nums, ++index);
}
public boolean linearSearch(int start, int value, int[] nums){
if(start >= nums.length)
return false;
if(nums[start] == value){
return true;
}else {
return linearSearch(start + 1, value, nums);
}
}