Reversing the order of sub-array using Recursion - java

I am trying to reverse the order of a sub-array between the indices of start and end strictly using recursion. For example, if the subarray is 1,2,3,4 , it will become 4,3,2,1.
However, I am getting the following runtime error:
java.lang.ArrayIndexOutOfBoundsException: -1
at finalExam.reverse(finalExam.java:13)
at finalExam.reverse(finalExam.java:17)
I am not sure how to fix this problem.
Thanks.
double[] reverse (double[] a, int start, int end) {
if (start == end) {return a;}
else {
a[start] = a[end];
a[end] = a[start];}
return reverse (a, start+1, end-1);
}

(Since you mention the exam is over). Here are the problems with your code:
Your check should be start >= end
Your code for swapping two numbers is incorrect.
Here is the correct solution:
public static double[] reverse (double[] a, int start, int end) {
if (start >= end) {
return a;
}
else {
// this code will swap two elements
double temp = a[start];
a[start] = a[end];
a[end] = temp;
}
return reverse (a, start+1, end-1);
}

Related

Recursive to iterative when using recursive-result for other calculatons

In theory it should be possible to write every recursive method into an iterative one.
I know it's pretty easy when the recursive function is tail-recursive. For example, calculating a factorial can be done like this recursive:
// Recursive:
long fact(long n){
return fact(n, 1);
}
long fact(long n, long r){
return n==1 ?
r
:
fact(n-1, r*n);
}
Try it online.
or like this iterative:
// Iterative:
int fact(int n){
int r = 1;
for(; n>1; n--)
r *= n;
return r;
}
Try it online.
This is pretty easy, because we don't use the result of the recursive method for something else, and we only have a single recursive call, where we decrease n by 1 ever iteration.
I also know you should keep a stack for most recursive to iterative conversions. For example, doing a quick-sort can be done like this recursive:
// Recursive:
void quicksort(int[] array, int left, int right){
if(left >= right) return;
int index = partition(array, left, right);
quicksort(array, left, index-1);
quicksort(array, index+1, right);
}
Try it online.
or like this iterative:
// Iterative:
void quicksort(int[] array, int left, int right){
int[] stack = new int[1024]; // Example size, alternative an actual java.util.Stack could be used
int i=0;
stack[i++] = left;
stack[i++] = right;
while(i>0){
right = stack[--i];
left = stack[--i];
if(left >= right) continue;
int index = partition(array, left, right);
stack[i++] = left;
stack[i++] = index-1;
stack[i++] = index+1;
stack[i++] = right;
}
}
Try it online.
But I now want to convert the following recursive method into its iterative form as well:
// Recursive:
int f(int n){
return n<1 ?
0
:
n%2+1 + 3*f(n/2);
}
Try it online.
In this case it uses the recursive result, and multiply that result by 3. I'm not entirely sure how to make this iterative as well. I tried something like this:
// Iterative:
int f(int n){
int[] stack = new int[1024]; // Example size, alternative an actual java.util.Stack could be used
int i=0;
stack[i++] = n;
while(i > 0){
n = stack[--i];
if(n < 1)
stack[i++] = 0;
stack[i++] = n%2+1 + 3*stack[--i];
}
return stack[0];
}
Which obviously it not going to work, since i=1 before it enters the while, then it becomes 0 at n = stack[--i], then 1 again at stack[i++] = n%2+1 + ..., and then 0 again at 3*stack[--i], so it stops after the first iteration, and simply returns stack[0]. How should I convert this recursive method above to an iterative one when I use the result of the recursive-call with other calculations (multiplying by 3 in this case)?
As for the reason why: I want to port this recursive method above to a stack-based language which doesn't have any functions and therefore I'll need the iterative approach (with stack).
Ok, I've been able to figure it out. I first need to fill the entire stack with the n%2+1 parts, dividing 2 every iteration. And as soon as n < 1, I need an inner loop to calculate the result.
Here is what I ended up with:
// Recursive:
int f(int n){ // i.e. n=2
int[] stack = new int[1024]; // Example size, alternative an actual java.util.Stack could be used
int i=0;
while(i >= 0){
stack[i++] = n%2+1;
n/=2;
if(n < 1){
while(i > 0){
n = 3*n + stack[--i];
}
return n;
}
}
return -1; // It should never come here, but the method need a return-statement
}
Try it online.
I ended up with something quiet similar (saw your self-answer only after)
int iterf(int n){
//can also be implemented with an array. easier with list.
List<Integer> sum = new ArrayList<>();
while (true) {
if( n < 1 ) { //equivalent to if(n<1) return 0;
sum.add(0);
break;
}
//for each n, fill list with the fixed argument part: (n%2)+1
sum.add((n%2)+1);
n=n/2;
}
//add to each list element 3 time the next element
//equivalent to 3*f(n/2);
for(int i = sum.size()-2; i >=0; i--) {
sum.set(i, sum.get(i) + (3*(sum.get(i+1))));
}
return sum.get(0);
}

Finding max and min using divide and conquer approach

I know this is a silly question,but I'm not getting this at all.
In this code taken from http://somnathkayal.blogspot.in/2012/08/finding-maximum-and-minimum-using.html
public int[] maxMin(int[] a,int i,int j,int max,int min) {
int mid,max1,min1;
int result[] = new int[2];
//Small(P)
if (i==j) max = min = a[i];
else if (i==j-1) { // Another case of Small(P)
if (a[i] < a[j]) {
this.max = getMax(this.max,a[j]);
this.min = getMin(this.min,a[i]);
}
else {
this.max = getMax(this.max,a[i]);
this.min = getMin(this.min,a[j]); }
} else {
// if P is not small, divide P into sub-problems.
// Find where to split the set.
mid = (i + j) / 2;
// Solve the sub-problems.
max1 = min1 = a[mid+1];
maxMin( a, i, mid, max, min );
maxMin( a, mid+1, j, max1, min1 );
// Combine the solutions.
if (this.max < max1) this.max = max1;
if (this.min > min1) this.min = min1;
}
result[0] = this.max;
result[1] = this.min;
return result;
}
}
Let's say the array is 8,5,3,7 and we have to find max and min,
Initial values of max and min=arr[0]=8;
First time list will be divided into 8,5
We call MaxMin with max=8 and min=8,since i==j-1,we will get max=8,min=5,
Next time list will be divided into [3,7],
min1=max1=arr[mid+1]=3,
We call MaxMin with max=3 and min=3.Since i is equal to j-1,we will get max=7,min=3,
Next the comparison is performed between max1,max and min1,min ,
Here is my confusion,
The values of max and max1 here is 8 and 7 respectively,but how???
We have not modified max1 anywhere,then how it will have a value 7,
As per my understanding,we had called MaxMin with max=3 and min=3 and then updated max=7 and min=3,but we had not returned these updated values,then how the values of max1 and min1 got updated,
I'm stuck at this,please explain.
Thanks.
It looks like you are updating 2 external values (not in this function) which are this.min and this.max
All you do is splitting in pieces of 1 or 2 elements and then update this.min and this.max, so you could also directly scan the array and check all int value for min/max. This is not really doing divide and conquer.
Here is a solution that really use divide and conquer :
public int[] maxMin(int[] a,int i,int j) {
int localmin,localmax;
int mid,max1,min1,max2,min2;
int[] result = new int[2];
//Small(P) when P is one element
if (i==j) {
localmin = a[i]
localmax = a[i];
}
else {
// if P is not small, divide P into sub-problems.
// where to split the set
mid = (i + j) / 2;
// Solve the sub-problems.
int[] result1 = maxMin( a, i, mid);
int[] result2 = maxMin( a, mid+1, j);
max1 = result1[0];
min1 = result1[1];
max2=result2[0];
min2=result2[1];
// Combine the solutions.
if (max1 < max2) localmax = max2;
else localmax=max1;
if (min1 < min2) localmin = min1;
else localmin=min2;
}
result[0] = localmax;
result[1] = localmin;
return result;
}
Frankly that blogger's code looks like a mess. You should have no confidence in it.
Take is this line early on:
if (i==j) max = min = a[i];
The values passed INTO the function, max and min, aren't ever used in this case, they are just set, and then lost forever. Note also if this line runs, the array result is neither set nor returned. (I would have thought that the compiler would warn that there are code paths that don't return a value.) So that's a bug, but since he never uses the return value anywhere it might be harmless.
The code sometimes acts like it is returning values through max and min (can't be done), while other parts of the code pass back the array result, or set this.max and this.min.
I can't quite decide without running it if the algorithm will ever return the wrong result. It may just happen to work. But its a mess, and if it were written better you could see how it worked with some confidence. I think the author should have written it in a more purely functional style, with no reliance on external variables like this.min and this.max.
Parenthetically, I note that when someone asked a question in the comments he replied to the effect that understanding the algorithm was the main goal. "Implementation [of] this algorithm is very much complex. For you I am updating a program with this." Gee, thanks.
In short, find a different example to study. Lord of dark posted a response as I originally wrote this, and it looks much improved.
Code
import java.util.Random;
public class MinMaxArray {
private static Random R = new Random();
public static void main(String[] args){
System.out.print("\nPress any key to continue.. ");
try{
System.in.read();
}
catch(Exception e){
;
}
int N = R.nextInt(10)+5;
int[] A = new int[N];
for(int i=0; i<N; i++){
int VAL = R.nextInt(200)-100;
A[i] = VAL;
}
Print(A);
Pair P = new Pair(Integer.MIN_VALUE, Integer.MAX_VALUE);
P = MinMax(A, 0, A.length-1);
System.out.println("\nMin: " + P.MIN);
System.out.println("\nMax: " + P.MAX);
}
private static Pair MinMax(int[] A, int start, int end) {
Pair P = new Pair(Integer.MIN_VALUE, Integer.MAX_VALUE);
Pair P_ = new Pair(Integer.MIN_VALUE, Integer.MAX_VALUE);
Pair F = new Pair(Integer.MIN_VALUE, Integer.MAX_VALUE);
if(start == end){
P.MIN = A[start];
P.MAX = A[start];
return P;
}
else if(start + 1 == end){
if(A[start] > A[end]){
P.MAX = A[start];
P.MIN = A[end];
}
else{
P.MAX = A[end];
P.MIN = A[start];
}
return P;
}
else{
int mid = (start + (end - start)/2);
P = MinMax(A, start, mid);
P_ = MinMax(A, (mid + 1), end);
if(P.MAX > P_.MAX){
F.MAX = P.MAX;
}
else{
F.MAX = P_.MAX;
}
if(P.MIN < P_.MIN){
F.MIN = P.MIN;
}
else{
F.MIN = P_.MIN;
}
return F;
}
}
private static void Print(int[] A) {
System.out.println();
for(int x: A){
System.out.print(x + " ");
}
System.out.println();
}
}
class Pair{
public int MIN, MAX;
public Pair(int MIN, int MAX){
this.MIN = MIN;
this.MAX = MAX;
}
}
Explanation
This is the JAVA code for finding out the MIN and MAX value in an Array using the Divide & Conquer approach, with the help of a Pair class.
The Random class of JAVA initializes the Array with a Random size N ε(5, 15) and with Random values ranging between (-100, 100).
An Object P of the Pair class is created which takes back the return value from MinMax() method. The MinMax() method takes an Array (A[]), a Starting Index (start) and a Final Index (end) as the Parameters.
Working Logic
Three different objects P, P_, F are created, of the Pair class.
Cases :-
Array Size -> 1 (start == end) : In this case, both the MIN and the MAX value are A[0], which is then assigned to the object P of the Pair class as P.MIN and P.MAX, which is then returned.
Array Size -> 2 (start + 1 == end) : In this case, the code block compares both the values of the Array and then assign it to the object P of the Pair class as P.MIN and P.MAX, which is then returned.
Array Size > 2 : In this case, the Mid is calculated and the MinMax method is called from start -> mid and (mid + 1) -> end. which again will call recursively until the first two cases hit and returns the value. The values are stored in object P and P_, which are then compared and then finally returned by object F as F.MAX and F.MIN.
The Pair Class has one method by the same name Pair(), which takes 2 Int parameters, as MIN and MAX, assigned to then as Pair.MIN and Pair.MAX
Further Links for Code
https://www.techiedelight.com/find-minimum-maximum-element-array-minimum-comparisons/
https://www.enjoyalgorithms.com/blog/find-the-minimum-and-maximum-value-in-an-array

how to understand quick sort algorithm

I am learning quick sort in java, according to the material I have. The best case is the pivot is the median, worst case is when one side of the pivot is always empty.
For the following code, is "indexPartition" the pivot? What kind of parameters do you put in the following function so it will run in the worst situation?
private void quickSortSegment(E[] list, int start, int end)
{
if (end-start>1)
{
int indexPartition = partition(list, start, end);
quickSortSegment(list, start, indexPartition);
quickSortSegment(list, indexPartition+1, end);
}
}
private int partition(E[] list, int start, int end)
{
E temp;
E partitionElement = list[start];
int leftIndex = start;
int rightIndex = end-1;
while (leftIndex<rightIndex)
{
while (list[leftIndex].compareTo(partitionElement) <= 0 && leftIndex<rightIndex)
{
leftIndex++;
}
while (list[rightIndex].compareTo(partitionElement) > 0)
{
rightIndex--;
}
if (leftIndex<rightIndex)
{
temp = list[leftIndex];
list[leftIndex] = list[rightIndex];
list[rightIndex] = temp;
}
}
list[start] = list[rightIndex];
list[rightIndex] = partitionElement;
return rightIndex;
}
No the pivot is partitionElement. It also seems this code always selects the first element in the sequence to be the pivot. The function will run in all cases including the worst cases, but it will perform badly(have square complexity).
Different people propose different solutions for selecting the pivot but I personally like this one: Select 3 random elements from the interval in consideration, compute their average and use it as pivot.
This video along with the wikipedia article should clear things up. Wikipedia is pretty awesome for explaining sorting algorithms. With respect to your question, indexPartition is rightIndex, which is the index of partitionElement, the pivot.
Something wrong with this method partition(), e.g. for {3,1,2} we'll get {1,3,2}:
public class CompareApp {
public static void main(String... args) {
Integer[] arr = {3, 1, 2};
quickSortSegment(arr, 0, 2);
for (Integer i : arr) System.out.println(i);
}
private static <E extends Comparable> void quickSortSegment(E[] list, int start, int end) {
if (end - start > 1) {
int indexPartition = partition(list, start, end);
quickSortSegment(list, start, indexPartition);
quickSortSegment(list, indexPartition + 1, end);
}
}
private static <E extends Comparable> int partition(E[] list, int start, int end) {
E temp;
E partitionElement = list[start];
int leftIndex = start;
int rightIndex = end - 1;
while (leftIndex < rightIndex) {
while (list[leftIndex].compareTo(partitionElement) <= 0 && leftIndex < rightIndex) {
leftIndex++;
}
while (list[rightIndex].compareTo(partitionElement) > 0) {
rightIndex--;
}
if (leftIndex < rightIndex) {
temp = list[leftIndex];
list[leftIndex] = list[rightIndex];
list[rightIndex] = temp;
}
}
list[start] = list[rightIndex];
list[rightIndex] = partitionElement;
return rightIndex;
}}
java system.compare.CompareApp
1
3
2

Lexicographic Quick Sort

I try to sort an array of Strings in lexicographical order by using the quick sort algorithm in java. The array is read in via the terminal using a Scanner and saved in an ArrayList. This ArrayList is later converted to an array where I (try to) apply the quick sort algorithm on.
I have two methods:
private static void sortA(String[] s, int start, int end) {
if (end > start) {
int pivot = partition(s, start, end);
sortA(s, start, pivot - 1);
sortA(s, pivot + 1, end);
}
}
private static int partition(String[] s, int start, int end) {
String pivot = s[end];
int left = start;
int right = end;
String temp = "";
do {
while ((s[left].compareTo(pivot) <= 0) && (left < end))
left++;
while ((s[right].compareTo(pivot) > 0) && (right > start))
right--;
if (left < right) {
temp = s[left];
s[left] = s[end];
s[right] = temp;
printRow(s);
}
} while (left < right);
temp = s[left];
s[left] = s[end];
s[end] = temp;
return left;
}
The code seems to randomly work fine and then suddenly not. For example the array {"java", "application", "system"} sorts fine to {"application", "java", "system"}. The array {"library", "content", "bin"} sorts to {"bin", "library", "contents"}, which is not the lexicographic order. Of course a computer does not work randomly so there must be something wrong with my code. I tried to work out an example on paper but then I'll find something completely wrong. However I based my code on an quick sort implementation of sorting a double array so I don't think I made a big reasoning error.
Thanks in advance.
You are splitting the array in the wrong way:
The correct splitting is "pivot-1" "pivot"
sortA(s, start, pivot-1);
sortA(s, pivot, end);

JAVA - Binary search - return index of key

I have the following problem I need to solve, but is strugling a bit. Would really appreciate it if someone can help.
In short in comes down to the following:
If the search key is in the array - it returns the smallest index i for which a[i] is equal to the key
If the search key is not in the array but greater - it returns the smallest index i as -i where a[i] is greater than the key
If the search key is not in the array but smaller - it returns -j where j is the index of the last element in the array
I have the code of searching for the key, but I'm not sure how to return the indexes as mentioned above...
import java.util.Arrays;
public class BinarySearchIndex2 {
// a working recursive version
public static int search(String key, String[] a) {
return search(key, a, 0, a.length);
}
public static int search(String key, String[] a, int lo, int hi) {
// possible key indices in [lo, hi)
if (hi <= lo) return -1;
int mid = lo + (hi - lo) / 2;
int cmp = a[mid].compareTo(key);
if (cmp > 0) return search(key, a, lo, mid);
else if (cmp < 0) return search(key, a, mid+1, hi);
else return mid;
}
public static void main(String[] args) {
String key = args[0];
int sizeoflist = StdIn.readInt();
String[] a = new String[sizeoflist];
int counter = 0; //counter for while loop to fill array a
while (!StdIn.isEmpty()){
a[counter] = StdIn.readString();
counter++;
}
Arrays.sort(a); // sort the words (if needed)
if ( search(key, a) < 0) ; /* System.out.println();*/
else if ( search(key, a) > 0 ) ;
else if ( search(key, a) = 0 ) ;
}
}
Would be really glad if someone can help me with this matter...
Thanks!
String.compareTo performs a lexicographical comparison. This means that it can decide that "50">"100", whereas clearly 50<100 is what you would expect. This will affect your Arrays.sort call so your Array is already messed up.
Is it a must to have public static int search(String key, String[] a) as your API?
If you can change it to be public static int search(int key, int[] a) it will make your API work (assuming you don't have any bugs I missed).
Hope this was what you were referring to.
Edit: some fine tuning to the problem analysis.
The important point is here:
if (hi <= lo) return -1;
This occurs when you got an sub-array to search of size zero, which means that the element is not there. Now think: what does the specification say about the return value here?

Categories

Resources