For a classic binarySearch on an array of java Strings (say String[] a), which is the correct way of calling the search method? is it
binarySearch(a,key,0,a.length)
or
binarySearch(a,key,0,a.length-1)
I tried both for the below implementation,and both seems to work.. Is there a usecase where either of these calls can fail?
class BS{
public static int binarySearch(String[] a,String key){
return binarySearch(a,key,0,a.length);
//return binarySearch(a,key,0,a.length-1);
}
public static int binarySearch(String[] a,String key,int lo,int hi) {
if(lo > hi){
return -1;
}
int mid = lo + (hi - lo)/2;
if(less(key,a[mid])){
return binarySearch(a,key,lo,mid-1);
}
else if(less(a[mid],key)){
return binarySearch(a,key,mid+1,hi);
}
else{
return mid;
}
}
private static boolean less(String x,String y){
return x.compareTo(y) < 0;
}
public static void main(String[] args) {
String[] a = {"D","E","F","M","K","I"};
Arrays.sort(a);
System.out.println(Arrays.toString(a));
int x = binarySearch(a,"M");
System.out.println("found at :"+x);
}
}
Consider the case where
a = [ "foo" ]
and you search key "zoo" with binarySearch(a,key,0,a.length);
The code will search for it in interval[0,1], see it should be right than that,
next recursion searches interval [1,1], causing an indexing of a[1] at line
if(less(key,a[mid])){
resulting in a array out of bounds error.
The second solution will work fine.
I think the second approach will be safe.
Consider this case - you have an array of 9 elements and the key is situated at the last index (8-th element). Then you might have a method call like this if you follow the first approach -
binarySearch(a, key, 9, 9);
Now, in that method execution, the integer division in the following line will result in 9 -
int mid = 9 + (9 - 9)/2;
and you will be indexing your array with 9 in the next line -
if( less(key,a[mid]) ) { // You'll face ArrayIndexOutOfBoundException
....
}
which will be invalid and cause ArrayIndexOutOfBoundException.
The second approach however will be just fine.
Related
public class binsearch {
public static void main(String args[])
{
int arr[]={2,45,-21,56,23};
int target=45;
int answer=binarysearch(arr, target);
System.out.println(answer);
}
static int binarysearch(int arr[],int target)
{
int start=0;
int end=arr.length-1;
int mid=start+end/2;
while(start<=end)
{
if(target<arr[mid])
{
mid=end-1;
}
else if(target>arr[mid])
{
mid=mid+1;
}
else
{
return mid;
}
}
return -1;
}
}
I have tried running this code multiple times but it just doesnt run. I dont think there is any problem with the logic for binary search in this code. Please do help.Thank you.
Your code runs. It has an infinite loop so it never terminates.
In order for a binary search to work. The array must be sorted in ascending order. So just sort the array before you do the binary search. Below code uses class java.util.Arrays to sort the array but you can sort it anyway you like. Just make sure that the array is sorted before you do the binary search.
Also, the calculation of mid needs to be inside the while loop because it always changes since its value is determined by the values of both start and end and those values are changed inside the while loop.
Note that I changed the name of the class so as to adhere to Java naming conventions. The conventions make it easier for other people to read and understand your code.
import java.util.Arrays;
public class BinSearch {
static int binarysearch(int arr[], int target) {
int start = 0;
int end = arr.length - 1;
while (start <= end) {
int mid = start + ((end - start) / 2);
if (target < arr[mid]) {
end = mid - 1;
}
else if (target > arr[mid]) {
start = mid + 1;
}
else {
return mid;
}
}
return -1;
}
public static void main(String[] args) {
int arr[] = {2, 45, -21, 56, 23};
Arrays.sort(arr);
int target = 45;
int answer = binarysearch(arr, target);
System.out.println(answer);
}
}
The answer is 3 because, after the sort, 45 is the second last element in the [sorted] array because it is the second largest number in the array.
If you want to search without sorting the array then a binary search is not appropriate.
I'm using Java.
I need to implement a recursive function that calculates the difference between each two values and returns for me array in size 2 [MAXIMUM_DIFF, STARTINDEX].
For the following array:
arr = {1, 4, 60, -10, 2, 7, 56, -10}
The recursive method returns array in size 2: [70,2] because the maximum difference is 70 (60-(-10)=70) and the index of 60 is 2.
I have 90% from the solution:
public static int[] getMax(int[] arr) {
int [] retArr = new int[2];
if(arr.length == 1)
return retArr;
else {
return getMax(arr, retArr);
}
}
public static int[] getMax(int[] arr, int[] retArr) {
if(retArr[1] == arr.length - 1)
return retArr;
int currentMaxVal = arr[retArr[1]] - arr[retArr[1] + 1];
if(currentMaxVal > retArr[0]) {
retArr[0] = currentMaxVal;
}
retArr[1] = retArr[1] + 1;
return getMax(arr, retArr);
}
But the result is[70,7] instead of [70,2] because this line retArr[1] = retArr[1] + 1;
This is because I don't know where to save the index, So how can I save the index?
*I'm not sure about the second param of getMax(int [] arr, int []retArr)
Its can be different maybe
I cant add another parameters, Maybe to change the second param of getMax(int [] arr, int []retArr), And I can't use static variables
if(currentMaxVal > retArr[0])
{
retArr[0] = currentMaxVal;
}
retArr[1] = retArr[1] + 1;
Should be
if(currentMaxVal > retArr[0])
{
retArr[0] = currentMaxVal;
retArr[1] = currentIndex;
}
And currentIndex should be an additional parameter passed to the function. (and other references to current index updated accordingly)
UPDATE:
I think the point here is to understand "divide and conquer", where you break up the problem into a smaller problem, and then sort through for the best one. Something like this (if a bit more awkward then a normal case)
public static int[] getMax(int[] arr, int[] retArr) {
// Return case
if (retArr[1] >= arr.length - 1)
return new int[] { Integer.MIN_VALUE, retArr[1] };
// Save context
int index = retArr[1];
int value = arr[index] - arr[index + 1];
// Call recursion
retArr[1]++;
int[] temp = getMax(arr, retArr);
// Return best between current case and recursive case
if (temp[0] > value)
return temp;
else
return new int[] { value, index };
}
Each call (or stack) of the recursive function is its own context. That means variables declared in it won't be overwritten in the recursive calls. The idea is that you break a hard problem down recursively until you can't break it down any further. Then you solve it by putting together the results of each call one at a time until you have your final answer. (This works better with less trivial cases like the fibonacci sequence) Also note that anything that can be done in a loop will always be more efficient then recursion.
I have written a java program to add elements in an array using Linear Recursion. The output obtained is not as expected. Can anyone point what is wrong with this program?
public class TestSum {
public int count = 0;
public int sum(int[] a){
count++;
if(a.length == count){
return a[count -1];
}
return sum(a) + a[count -1] ;
}
public static void main(String[] args) {
int[] a = {1,2,3};
int val = new TestSum().sum(a);
System.out.println(val);
}
}
I am expecting the output as 6 but obtained is 9. What is wrong?
Strangely if I change the order of addition i.e. return a[count -1] + sum(a); then it gives output as 6.
Generally, recursive programs that are not re-entrant (i.e. relying on external state) are suspicious. In your particular case count will change between invocations of sum, making the behavior hard to trace, and ultimately resulting in the error that you observe.
You should pass the index along with the array to make it work:
// The actual implementation passes the starting index
private static int sum(int[] a, int start){
if(a.length == start){
return 0;
}
return sum(a, start+1) + a[start];
}
// Make sure the method can be called with an array argument alone
public static int sum(int[] a) {
return sum(a, 0);
}
Unlike an implementation that increments the count external to the method, this implementation can be called concurrently on multiple threads without breaking.
I am doing this assignment and I am having trouble writing this method recursively.
I have this way to do it which is effective but not recursive:
public static <T extends Comparable< ? super T>> T getLargest(T [] a, int low,
int high)
{
if(low>high)
throw new IllegalArgumentException();
return Collections.max(Arrays.asList(Arrays.copyOfRange(a, low, high)));
So from there I went to this one, which kind of extends it but is not recursive either:
T[] arrCopy = (T[]) new Object[high-low];
for(int i=low;i<high;i++){
if(a[i].compareTo(a[i-1])>0)
arrCopy[i]=a[i];
else
arrCopy[i]=a[i+1];
}
return arrCopy[0];
And I've been working on it for hours and can't seem a way to make it recursive and make it work.
Any help and ideas are greatly appreciated!
Well, here is a template for turning a for-loop into a tail-recursive method:
//iterative version
public Object getIteratively(Object[] a) {
Object retVal = null;
for (int i = 0; i < a.length; a++ ) {
//do something
}
return retVal;
}
//recursive version
public Object getRecursively(Object[] a) {
doGetRecursively(a, 0, null);
}
private Object doGetRecursively(Object[] a, int i, Object retVal) {
if ( i == a.length ) {
return retVal;
}
//do something
return doGetRecursively(a, i+1, retVal);
}
Why you would ever want to do this in a non-functional language is beyond me though.
In this case //do something would be the same in both cases, e.g.:
if ( a[i].compareTo(retVal) > 0 ) {
retVal = a[i];
}
First, your method signature is incorrect. You do not need a 'low'. You should take an array/list as input and return the largest element. You may find however that you want a secondary method that requires extra arguments.
When approaching recursion and you're stuck, it's often best to identify your base case(s) first, then deal with your recursive case(s) next.
Your base case is the simplest case in which you know the answer. In this problem, you know what the largest element is right away if the size of your list is 1 - you just return the only element. You may want to think about the case where your list is empty as well.
Your recursive case then, is whenever your list has size greater than 1. In your recursive case, you want to try and 'break a piece off' and then send the rest to a recursive call. In this case, you can look at the first element in the list, and compare it to the result you get from a recursive call on the rest of the list.
This would be the right answer:
T tmp = a[low];
for(int i=0;i<=high;i++){
if(a[i].compareTo(tmp)>0){
tmp = a[i];
getLargest(a,i,high);
}
}
return tmp;
Okay before this gets out of hand, here's a simple iterative and the equivalent recursive solution to this - implemented with ints though so you have to change it a bit ;)
public static int getLargest(int[] vals) {
int max = vals[0];
for (int i = 1; i < vals.length; i++) {
max = Math.max(max, vals[i]);
}
return max;
}
public static int getLargestRec(int[] vals) {
return getLargestRec(vals, 0, vals.length);
}
private static int getLargestRec(int[] vals, int low, int high) {
if (low + 1 == high) {
return vals[low];
}
int middle = low + (high - low) / 2;
int left = getLargestRec(vals, low, middle);
int right = getLargestRec(vals, middle, high);
return Math.max(left, right);
}
public static void main(String[] args) {
int[] vals = {5, 23, 32, -5, 4, 6};
System.out.println(getLargestRec(vals));
System.out.println(getLargest(vals));
}
Note that as usual for recursive problems the lower bound is inclusive and the higher bound is exclusive. Also we could implement this differently as well, but the usual divide & conquer approach is rather useful and lends itself nicely to parallelization with a fork framework, so that's fine. (And yes for an empty array both versions will fail)
I have a divide and conquer method to find the i th smallest element from an array. Here is the code:
public class rand_select{
public static int Rand_partition(int a[], int p, int q, int i) {
//smallest in a[p..q]
if ( p==q) return a[p];
int r=partition (a,p,q);
int k=r-p+1;
if (i==k) return a[r];
if (i<k){
return Rand_partition(a,p,r-1,i);
}
return Rand_partition(a,r-1,q,i-k);
}
public static void main(String[] args) {
int a[]=new int []{6,10,13,15,8,3,2,12};
System.out.println(Rand_partition(a,0,a.length-1,7));
}
public static int partition(int a[],int p,int q) {
int m=a[0];
while (p < q) {
while (p < q && a[p++] < m) {
p++;
}
while (q > p && a[q--] > m) {
q--;
}
int t = a[p];
a[p] = a[q];
a[q] = t;
}
int k=0;
for (int i=0; i < a.length; i++) {
if ( a[i]==m){
k=i;
}
}
return k;
}
}
However, I get an exception when run: java.lang.ArrayIndexOutOfBoundsException.
I was able to fix a few bugs. A minor one is this line:
return Rand_partition(a,r-1,q,i-k);
^
Instead, you want this:
return Rand_partition(a,r+1,q,i-k);
^
That's because you have partitioned a[p..q] into three parts as follows:
a[p..r-1], a[r], a[r+1..q]
Your original code handles the a[r] and a[p..r-1] case fine, but messes up on the a[r+1..q] by using r-1 instead.
I was also able to correct and simplify partition:
public static int partition(int a[],int p,int q){
int m=a[p]; // not m[0], you want to partition m[p..q]!!!
while ( p<q){
while (p<q && a[p] <m){ // don't do p++ here!
p++;
}
while (q>p && a[q]>m){ // don't do q-- here!
q--;
}
int t=a[p];
a[p]=a[q];
a[q]=t;
}
return p; // no need to search!!!
}
Your original code had extraneous p++ and q--. Also, the search for where the pivot is is unnecessary. It's where p and q meet.
On naming conventions
Please follow Java naming conventions:
Class names should be nouns, in mixed case with the first letter of each internal word capitalized. Methods should be verbs, in mixed case with the first letter lowercase, with the first letter of each internal word capitalized.
Related questions
How is this statement making sense? (Sun’s naming convention for Java variables)
Unfortunately the naming convention document above has one glaring error
On array declarations
Also, do not make a habit of declaring arrays like this:
int x[];
You should instead put the brackets with the type, rather than with the identifier:
int[] x;
Related questions
Is there any difference between Object[] x and Object x[] ?
Difference between int[] myArray and int myArray[] in Java
in array declaration int[] k,i and int k[],i
These declarations result in different types for i!
Assuming this isn't homework where you need do it this way, and it's not in the critical path (which is a likely guess), just sort the array and grab the value at index i.
public static getIthSmallest(final int[] myArray, final int i) {
if (i < 0) {
System.err.println("You're going to get an ArrayIndexOutOfBoundsException.");
}
if (i >= myArray.length) {
System.err.println("You're going to get an ArrayIndexOutOfBoundsException.");
}
Arrays.sort(myArray);
return myArray[i];
}
No clue what your bug is (I dislike Java :)
The simple solution (O(n) average, O(n^2) worst case) to this problem is copy the source to a nice simple implementation of qsort and make it only recurse on the side that contains the position you care about. It should be about 5 lines of code different so it should be easy to do.
If i is small there is a O(n + log(n)*i*log(i)) solution):
int FindI(int[] array, int i)
{
int[] tmp = array[0..i].dup; // copy first i elements;
sort(tmp); // sort, low to high
foreach(j in array[i..$]) // loop over the rest
if(j < tmp[0])
{
tmp[0] = j;
sort(tmp);
}
return tmp[0];
}
The algorithm you're attempting to implement is called Quickselect. Here is a link to working code using a median-of-three partitioning strategy.
You can use public static T min(Collection coll, Comparator comp) in Collections.