I am working on this famous interview question on removing duplicate elements in array without using auxillary storage and preserving the order;
I have read a bunch of posts; Algorithm: efficient way to remove duplicate integers from an array, Removing Duplicates from an Array using C.
They are either implemented in C (without explanation) or the Java Code provided just fails when there is consecutive duplicates such as [1,1,1,3,3].
I am not quite confident with using C, my background is Java. So I implemented the code myself;
it follows like this:
use two loops, the outer-loop traverses the array and inner loop checks for duplicates and if present replace it with null.
Then I go over the duplicate-replaced-null array and remove null elements and replacing it with the next non-null element.
The total run-time I see now is O(n^2)+O(n) ~ O(n^2). Reading the above posts, I understood this is the best we can do, if no sorting and auxiliary storage is allowed.
My code is here: I am looking for ways to optimize any further (if there is a possibility) or a better/simplisitc logic;
public class RemoveDup {
public static void main (String[] args){
Integer[] arr2={3,45,1,2,3,3,3,3,2,1,45,2,10};
Integer[] res= removeDup(arr2);
System.out.println(Arrays.toString(res));
}
private static Integer[] removeDup(Integer[] data) {
int size = data.length;
int count = 1;
for (int i = 0; i < size; i++) {
Integer temp = data[i];
for (int j = i + 1; j < size && temp != null; j++) {
if (data[j] == temp) {
data[j] = null;
}
}
}
for (int i = 1; i < size; i++) {
Integer current = data[i];
if (data[i] != null) {
data[count++] = current;
}
}
return Arrays.copyOf(data, count);
}
}
EDIT 1; Reformatted code from #keshlam throws ArrayIndexOutofBound Exception:
private static int removeDupes(int[] array) {
System.out.println("method called");
if(array.length < 2)
return array.length;
int outsize=1; // first is always kept
for (int consider = 1; consider < array.length; ++consider) {
for(int compare=0;compare<outsize;++compare) {
if(array[consider]!=array[compare])
array[outsize++]=array[consider]; // already present; advance to next compare
else break;
// if we get here, we know it's new so append it to output
//array[outsize++]=array[consider]; // could test first, not worth it.
}
}
System.out.println(Arrays.toString(array));
// length is last written position plus 1
return outsize;
}
OK, here's my answer, which should be O(N*N) worst case. (With smaller constant, since even worstcase I'm testing N against -- on average -- 1/2 N, but this is computer science rather than software engineering and a mere 2X speedup isn't significant. Thanks to #Alexandru for pointing that out.)
1) Split cursor (input and output advanced separately),
2) Each new value only has to be compared to what's already been kept, and compare can stop if a match is found. (The hint keyword was "incremental")
3) First element need not be tested.
4) I'm taking advantage of labelled continue where I could have instead set a flag before breaking and then tested the flag. Comes out to the same thing; this is a bit more elegant.
4.5) I could have tested whether outsize==consider and not copied if that was true. But testing for it would take about as many cycles as doing the possibly-unnecessary copy, and the majority case is that they will not be the same, so it's easier to just let a possibly redundant copy take place.
5) I'm not recopying the data in the key function; I've factored out the copy-for-printing operation to a separate function to make clear that removeDupes does run entirely in the target array plus a few automatic variables on the stack. And I'm not spending time zeroing out the leftover elements at the end of the array; that may be wasted work (as in this case). Though I don't think it would actually change the formal complexity.
import java.util.Arrays;
public class RemoveDupes {
private static int removeDupes(final int[] array) {
if(array.length < 2)
return array.length;
int outsize=1; // first is always kept
outerloop: for (int consider = 1; consider < array.length; ++consider) {
for(int compare=0;compare<outsize;++compare)
if(array[consider]==array[compare])
continue outerloop; // already present; advance to next compare
// if we get here, we know it's new so append it to output
array[outsize++]=array[consider]; // could test first, not worth it.
}
return outsize; // length is last written position plus 1
}
private static void printRemoveDupes(int[] array) {
int newlength=removeDupes(array);
System.out.println(Arrays.toString(Arrays.copyOfRange(array, 0, newlength)));
}
public static void main(final String[] args) {
printRemoveDupes(new int[] { 3, 45, 1, 2, 3, 3, 3, 3, 2, 1, 45, 2, 10 });
printRemoveDupes(new int[] { 2, 2, 3, 3 });
printRemoveDupes(new int[] { 1, 1, 1, 1, 1, 1, 1, 1 });
}
}
LATE ADDITION: Since folks expressed confusion about point 4 in my explanation, here's the loop rewritten without labelled continue:
for (int consider = 1; consider < array.length; ++consider) {
boolean matchfound=false;
for(int compare=0;compare<outsize;++compare) {
if(array[consider]==array[compare]) {
matchfound=true;
break;
}
if(!matchFound) // only add it to the output if not found
array[outsize++]=array[consider];
}
Hope that helps. Labelled continue is a rarely-used feature of Java, so it isn't too surprising that some folks haven't seen it before. It's useful, but it does make code harder to read; I probably wouldn't use it in anything much more complicated than this simple algorithm.
Here one version which doesn't use additional memory (except for the array it returns) and doesn't sort either.
I believe this is slightly worse than O(n*log n).
Edit: I'm wrong. This is slightly better than O(n^3).
public class Dupes {
private static int[] removeDupes(final int[] array) {
int end = array.length - 1;
for (int i = 0; i <= end; i++) {
for (int j = i + 1; j <= end; j++) {
if (array[i] == array[j]) {
for (int k = j; k < end; k++) {
array[k] = array[k + 1];
}
end--;
j--;
}
}
}
return Arrays.copyOf(array, end + 1);
}
public static void main(final String[] args) {
System.out.println(Arrays.toString(removeDupes(new int[] { 3, 45, 1, 2, 3, 3, 3, 3, 2, 1, 45, 2, 10 })));
System.out.println(Arrays.toString(removeDupes(new int[] { 2, 2, 3, 3 })));
System.out.println(Arrays.toString(removeDupes(new int[] { 1, 1, 1, 1, 1, 1, 1, 1 })));
}
}
and here's a modified version which doesn't shift all of the elements from after the dupe. Instead it simply switches the dupe with the last, non-matching element. This obviously can't guarantee order.
private static int[] removeDupes(final int[] array) {
int end = array.length - 1;
for (int i = 0; i <= end; i++) {
for (int j = i + 1; j <= end; j++) {
if (array[i] == array[j]) {
while (end >= j && array[j] == array[end]) {
end--;
}
if (end > j) {
array[j] = array[end];
end--;
}
}
}
}
return Arrays.copyOf(array, end + 1);
}
Here you have a worst case of O(n^2) where the return points to the first non unique element. So everything before it is unique.
Instead of C++ iterators indices in Java can be used.
std::vecotr<int>::iterator unique(std::vector<int>& aVector){
auto end = aVector.end();
auto start = aVector.begin();
while(start != end){
auto num = *start; // the element to check against
auto temp = ++start; // start get incremented here
while (temp != end){
if (*temp == num){
std::swap(temp,end);
end--;
}
else
temp++; // the temp is in else so that if the swap occurs the algo should still check the swapped element.
}
}
return end;
}
Java equivalent code: (the return will be an int which is the index of the first not unique element)
int unique(int[] anArray){
int end = anArray.length-1;
int start = 0;
while(start != end){
int num = anArry[start]; // the element to check against
int temp = ++start; // start get incremented here
while (temp != end){
if (anArry[temp] == num){
swap(temp,end); // swaps the values at index of temp and end
end--;
}
else
temp++; // the temp is in else so that if the swap occurs the algo should still check the swapped element.
}
}
return end;
}
The slight difference in this algo and yours is in your point 2. Where instead of replacing the current element with null you go with swapping it with the last possibly unique element which on the first swap is the last element of array, on second swap the second last and so on.
You might as well consider looking at the std::unique implementation in C++ which is linear in one less than the distance between first and last: Compares each pair of elements, and possibly performs assignments on some of them., but as it was noted by #keshlam it is used on sorted arrays only. The return value is the same as in my algo. Here is the code directly from the standard library:
template<class _FwdIt, class _Pr> inline
_FwdIt _Unique(_FwdIt _First, _FwdIt _Last, _Pr _Pred)
{ // remove each satisfying _Pred with previous
if (_First != _Last)
for (_FwdIt _Firstb; (_Firstb = _First), ++_First != _Last; )
if (_Pred(*_Firstb, *_First))
{ // copy down
for (; ++_First != _Last; )
if (!_Pred(*_Firstb, *_First))
*++_Firstb = _Move(*_First);
return (++_Firstb);
}
return (_Last);
}
To bring in a bit perspective - one solution in Haskell, it uses lists instead of arrays
and returns the reversed order, which can be fixed by applying reverse at the end.
import Data.List (foldl')
removeDup :: (Eq a) => [a] -> [a]
removeDup = foldl' (\acc x-> if x `elem` acc then acc else x:acc) []
Related
I am a beginner(first year uni student) programmer trying to solve this problem which i'm finding somewhat difficult. If you are to answer this question, don't provide me with a complex daunting algorithm that will leave me scratching my head. I'll really appreciate it if you explain it step my step (both logically/conceptually then through code)
The problem is as follows:image
I have tried to attempt it and my code only works for a certain case that i tested.
package com.company;
import java.lang.Math;
public class Main {
public static int[][] binary_partition(int array[], int k){
int x = (int) Math.pow(2,k);
int[][] partition = new int[((array.length/x)*2)][array.length/x];
int divisor = array.length/x;
if ((array.length % 2) != 0){
return partition;
}
if (divisor >= array.length-1){
return partition;
}
if (k==1){
return partition;
}
int p = 0;
for(int i=0;i<((array.length/x)*2);i++)
{
for (int j = 0; j<array.length/x;j++)
{
partition[i][j] = array[p];
p += 1;
}
}
return partition;
}
public static void main(String[] args){
int[] array = {3, 2, 4, 7, 8, 9, 2, 3};
int[][] result = binary_partition(array,2);
for (int[] x : result){
for (int y : x)
{
System.out.print(y + " ");
}
System.out.println();
}
}
}
Your question is unclear, but this solution creates a function that partitions an array with the right length into 2^k sets.
First, an interesting fact: using the bitshift operator << on an integer increases its value by a power of two. So to find out the size of your partition, you could write
int numPartitions = 1 << k; // Equivalent to getting the integer value of 2^k
With this fact, the function becomes
public static int[][] partition(int[] set, int k) {
if (set == null)
return null; // Don't try to partition a null reference
// If k = 0, the partition of the set is just the set
if (k == 0) {
int[][] partition = new int[1][set.length];
// Copy the original set into the partition
System.arraycopy(set, 0, partition[0], 0, set.length);
return partition;
}
int numPartitions = 1 << k; // The number of sets to partition the array into
int numElements = set.length / numPartitions; // The number of elements per partition
/* Check if the set has enough elements to create a partition and make sure
that the partitions are even */
if (numElements == 0 || set.length % numElements != 0)
return null; // Replace with an error/exception of your choice
int[][] partition = new int[numPartitions][numElements];
int index = 0;
for (int r = 0; r < numPartitions; r++) {
for (int c = 0; c < numElements; c++) {
partition[r][c] = set[index++]; // Assign an element to the partition
}
}
return partition;
}
There are a few lines of your code where the intention is not clear. For example, it is not clear why you are validating divisor >= array.length-1. Checking k==1 is also incorrect because k=1 is a valid input to the method. In fact, all your validation checks are not needed. All you need to validate is that array.length is divisible by x.
The main problem that you have seems to be that you mixed up the lengths of the resulting array.
The resulting array should have a length of array.length / x, and each of the subarrays should have a length of x, hence:
int[][] partition = new int[array.length/x][x];
If you also fix your bounds on the for loops, your code should work.
Your nested for loop can be rewritten as a single for loop:
for(int i = 0 ; i < array.length ; i++)
{
int index = i / x;
int subArrayIndex = i % x;
partition[index][subArrayIndex] = array[i];
}
You just need to figure out which indices a an element array[i] belongs by dividing and getting the remainder.
This is a code from Introduction to Java Programming about Merge Sort. This method uses a recursion implementation.
public class MergeSort {
2 /** The method for sorting the numbers */
3 public static void mergeSort(int[] list) {
4 if (list.length > 1) {
5 // Merge sort the first half
6 int[] firstHalf = new int[list.length / 2];
7 System.arraycopy(list, 0, firstHalf, 0, list.length / 2);
8 mergeSort(firstHalf);
9
10 // Merge sort the second half
11 int secondHalfLength = list.length - list.length / 2;
12 int[] secondHalf = new int[secondHalfLength];
13 System.arraycopy(list, list.length / 2,
14 secondHalf, 0, secondHalfLength);
15 mergeSort(secondHalf);
16
17 // Merge firstHalf with secondHalf into list
18 merge(firstHalf, secondHalf, list);
19 }
20 }
My question: is in Line 8 calls the recursion method back to "mergeSort"? If running from the beginning of the method, the "firstHalf" array will be created again and the length will be half short. I think the "firstHalf" can not created again and the length should not be changed if an array is defined already.
Here is the whole code link: Merge Sort Java.
This is beginner's way of thinking. Yes, exactly I thought the same when I encountered this before. I couldn't believe that the same array size can change dynamically. Understand this, in the below code, array l and array r are created with different sizes for every recursive call. Don't confuse on this.
Yes, this is never possible that the same array size changes dynamically for a beginner like you and me. But, there is an exception, well, there are exceptions. We will see them very often as we move forward.
Its recursion, in recursion things change dynamically and all this
changes are stored in a call stack.
Its confusing but its really interesting if you ponder over it. Its profound. Merge sort can be implemented in quite different ways, but the underlying concept of recursion is same. Don't get confused here, Its better you follow another way to do it, video:
Merge sort first takes a list or an array. Lets imagine the
a.length; #lenght of an array is 8
Now the end goal is to split the array recursively, till it reaches to a point where there are no-elements (only-one). And a single element is always sorted.
See the base case in the below code:
if(a.length<2) /*Remember this is the base case*/
{
return;
}
Once it reaches to single element, sort and merge them back. This way you get a complete sorted array which is easy to merge. The only reason we are doing all this non-sense is to get a better run-time algorithm which is O(nlogn).
Because, all the other sorting algos (insertion, bubble, and selection) will take O(n2), which is alot, too much indeed. So, humanity must figure out the better solution. Its a need for humanity, very important. I know its annoying, I had gone through this non-sense.
Please do some research on recursion before you attempt on this. Understand recursion clearly. Keep all this away. Take a simple recursion example and start working on it. Take a factorial example. Its a bad example but its easy to understand.
Top-down MergeSort
See my code, its nice and easy. Again, both are not easy to understand on your first attempt. You must get in touch with recursion before you attempt to understand these things. All the very best.
public class MergeSort
{
private int low;
private int high;
private int mid;
public static int[] a;
public MergeSort(int x)
{
a = new int[x];
a[0]=19;
a[1]=10;
a[2]=0;
a[3]=220;
a[4]=80;
a[5]=2000;
a[6]=56001;
a[7]=2;
}
public void division(int[] a)
{
low=0;
int p;
high = a.length;
mid = (high+low)/2;
if(a.length<2) /*Remember this is the base case*/
{
return;
}
else
{
int[] l = new int[mid];
int[] r = new int[high-mid];
/*copying elements from a into l and r*/
for(p=0;p<mid;p++)
l[p]=a[p];
for(int q=0;q<high-mid;q++, p++)
r[q]=a[p];
/*first recursive call starts from here*/
division(l);
division(r);
sortMerge(a, l, r);
}
}
public void sortMerge(int[] a, int[] l, int[] r)
{
int i=0, j=0, k=0;
/*sorting and then merging recursively*/
while(i<l.length && j<r.length)
{
if(l[i]<r[j])
{
a[k] = l[i]; /*copying sorted elements into a*/
i++;
k++;
}
else
{
a[k] = r[j];
j++;
k++;
}
}
/*copying remaining elements into a*/
while(i<l.length)
{
a[k] = l[i];
i++;
k++;
}
while(j<r.length)
{
a[k] = r[j];
j++;
k++;
}
}
/*method display elements in an array*/
public void display()
{
for(int newIndex=0;newIndex<a.length;newIndex++)
{
System.out.println(a[newIndex]);
}
}
public static void main(String[] args)
{
MergeSort obj = new MergeSort(8);
obj.division(a);
obj.display();
}
}
As it was pointed out by Emz: This is due to scope reasons. A local variable is a new object.
[
Local variables are declared by local variable declaration statements
(§14.4).
Whenever the flow of control enters a block (§14.2) or for statement
(§14.14), a new variable is created for each local variable declared
in a local variable declaration statement immediately contained within
that block or for statement.
A local variable declaration statement may contain an expression which
initializes the variable. The local variable with an initializing
expression is not initialized, however, until the local variable
declaration statement that declares it is executed. (The rules of
definite assignment (§16) prevent the value of a local variable from
being used before it has been initialized or otherwise assigned a
value.) The local variable effectively ceases to exist when the
execution of the block or for statement is complete.]1
Here is an alternative implementation of merge sort, this is bottom-up MergeSort
public class MergeSort {
public static void merge(int[]a,int[] aux, int f, int m, int l) {
for (int k = f; k <= l; k++) {
aux[k] = a[k];
}
int i = f, j = m+1;
for (int k = f; k <= l; k++) {
if(i>m) a[k]=aux[j++];
else if (j>l) a[k]=aux[i++];
else if(aux[j] > aux[i]) a[k]=aux[j++];
else a[k]=aux[i++];
}
}
public static void sort(int[]a,int[] aux, int f, int l) {
if (l<=f) return;
int m = f + (l-f)/2;
sort(a, aux, f, m);
sort(a, aux, m+1, l);
merge(a, aux, f, m, l);
}
public static int[] sort(int[]a) {
int[] aux = new int[a.length];
sort(a, aux, 0, a.length-1);
return a;
}
}
To understand how Merge Sort works you must understand two core data structures, Arrays and Stacks. Stacks are LIFO (Last in First Out). Method calls are executed using Stacks, so the last method call is executed first. Due to these factors, the Merge Sort has this unique behavior.
For example let's take an array as an input:
int[] input = new array[] {12, 11, 13, 5, 6, 7};
Now let's implement a Merge Sort on this array:
'''
class MergeSort
{
private static void merge_sort(int[] arr)
{
if (arr.length > 1)
{
int midpoint = arr.length / 2;
int[] l_arr = new int[midpoint];
int[] r_arr = new int[arr.length - midpoint];
int L_index = 0;
int R_index = 0;
// SORTING [ BEGIN ]
// [ BEGIN ]
// WHILE LOOP THAT IS FILLING THE LEFT ARRAY
//
while(L_index < l_arr.length )
{
l_arr[L_index] = arr[L_index];
if (L_index + 1 < l_arr.length)
{
l_arr[L_index + 1] = arr[L_index + 1];
L_index++;
}
L_index++;
}
// [ END ]
L_index = midpoint;
// [ BEGIN ]
// A WHILE LOOP THAT IS FILLING THE RIGHT ARRAY
//
while(R_index < r_arr.length)
{
r_arr[R_index] = arr[L_index];
if (R_index + 1 < r_arr.length)
{
r_arr[R_index + 1] = arr[L_index + 1];
L_index++;
R_index++;
}
L_index++;
R_index++;
}
// [ END ]
merge_sort(l_arr);
merge_sort(r_arr);
// SORTING [ END ]
// MEGING [ BEGIN ]
int l_index = 0;
int r_index = 0;
int index = 0;
while (l_index < l_arr.length && r_index < r_arr.length )
{
if (l_arr[l_index] <= r_arr[r_index])
{
arr[index] = l_arr[l_index];
l_index++;
}
else
{
arr[index] = r_arr[r_index];
r_index++;
}
index++;
}
while (l_index < l_arr.length)
{
arr[index] = l_arr[l_index];
l_index++;
index++;
}
while (r_index < r_arr.length)
{
arr[index] = r_arr[r_index];
r_index++;
index++;
}
// MEGING [ END ]
}
}
public static void main(String[] args)
{
int[] arr = new int[] {12, 11, 13, 5, 6, 7};
// BEGIN THE MERGE SORT
merge_sort(arr);
}
}
'''
When the merge sort is called the array is split into two arrays, the left array and right array. When the split happens, the left and right arrays are filled, and then recursion occurs.
The split happens always on the left until no split cannot be done, then the split transitions to the right half.
When the array reaches the size of one, the recursion stops, giving control to the previous method call. When no recursion cannot be performed, the code execution will go bellow the recursive method calls and the merge section of the algorithm will arrange the two halves in increasing / decreasing order and pass the control back to its own caller method instance.
Now the magic happens. When the array is given as a parameter to a method and it is sorted, the modifications done on the array parameter will affect the array that is within the caller method instance because, arrays are passed by reference and not by value. So this means that each time recursion occurs and it is passing the left or right half of the array, it is passing a reference to the left or right array and the modifications done by the called method instance will affect the array passed as a parameter in the caller method.
public static void main(String[] args) {
int[] a = { 1, 2, 3, 4, 5 };
int[] b = new int[5];
rekursiq(a, b, 0, 0, 1);
}
static void rekursiq(int[] a, int[] b, int index, int start, int check) {
if (index == b.length){
System.out.println(java.util.Arrays.toString(b));
} else {
for (int i = start; i < a.length; i++) {
b[index] = a[i];
rekursiq(a, b, index + 1, i + 1, check + 1);
}
}
}
Now my question is: Instead of b.length in the recursion bottom I want to place an int check, and make check go +1 on every going there, and do something.
while (check < b.length) go the if statement, else return; but I can't seem to 1) increase the value properly and 2) make this while correctly. I don't know why.
I think my best try was
static void rekursiq(int[] a, int[] b, int index, int start, int check) {
if (check > b.length) {
return;
} else {
if (index == check) {
System.out.println(java.util.Arrays.toString(b));
} else {
for (int i = start; i < a.length; i++) {
b[index] = a[i];
rekursiq(a, b, index + 1, i + 1, check + 1);
}
}
}
}
But it did not work, and I hope some one of you can tell me why and how to fix it.
The value of check does increase when the method is called recursively. However, the problem you have is independent of check.
The Problem
Let me start by repeating what abhishrp already briefly mentioned: In this particular case, you want to either use a loop to iterate over all elements in the array, or recursion, but not use a loop inside of your recursive method. The reason is the following: At each step in the recursion, you look at exactly one element: the element at position index.
The Solution
So, how would you recursively copy an array? Let us assume you have a source array (in your code a) and an empty destination array (in your code b). Now, we know how to copy a single element of the array, namely destination[index] = source[index], and we can imagine copying the array as copying the first element, and then copying the subarray starting at the second element. Note that knowing how to copy a single element in an array implies knowing how to copy an array containing only one element.
This leads us to the following recursion, which we will turn to code shortly after:
if the given index dereferences the last element in the array, then copy this last element.
otherwise, copy the element at the current index, and copy the subarray starting at the next index.
Or expressed in Java:
static void copyValuesFromSourceToDestinationStartingAtIndex(int[] source, int[] destination, int index) {
if (isIndexOfLastElementInArray(index, destination)) {
destination[index] = source[index];
} else {
destination[index] = source[index];
copyValuesFromSourceToDestinationStartingAtIndex(source, destination, index + 1);
}
}
static boolean isIndexOfLastElementInArray(int index, int[] array){
return index == array.length - 1;
}
Note that you have too many parameters in your code: The parameter check is really just index, as you want to check whether the index is still inside the bounds of the array. I don't really know what you intended to do with the variable start though - seems like somehow you got confused there because of the loop.
Sidenote
Also, a small justification on why the true-branch of the if-statement in the above code does copy the last element instead of returning nothing if the index is out of bounds as in your code. It's perfectly reasonable to do it like you did. The argument "We trivially know how to copy an empty array" just didn't seem as natural as "knowing how to copy a single element implies knowing how to copy an array consisting of a single element". I encourage you however to adjust the code to "copy an empty array" as a base-case, because it removes the duplication, and more importantly, allows you to copy empty arrays (for which the above implementation would fail horribly).
Code
I also tried to give a comparison between the iterative and the recursive approach:
public static void main(String[] args) {
int[] a = {1, 2, 3, 4, 5};
int[] copyOfAUsingIteration = copyArrayUsingIteration(a);
int[] copyOfAUsingRecursion = copyArrayUsingRecursion(a);
assert(Arrays.equals(copyOfAUsingIteration, copyOfAUsingRecursion));
assert(copyOfAUsingIteration != a);
assert(copyOfAUsingRecursion != a);
System.out.println(java.util.Arrays.toString(copyOfAUsingIteration));
System.out.println(java.util.Arrays.toString(copyOfAUsingRecursion));
}
static int[] copyArrayUsingIteration(int[] arrayToCopy) {
int[] result = new int[arrayToCopy.length];
for(int index = 0; index < result.length; index++){
result[index] = arrayToCopy[index];
}
return result;
}
static int[] copyArrayUsingRecursion(int[] arrayToCopy){
if (arrayToCopy.length == 0){
return new int[0];
} else {
int[] result = new int[arrayToCopy.length];
copyValuesFromSourceToDestinationStartingAtIndex(arrayToCopy, result, 0);
return result;
}
}
static void copyValuesFromSourceToDestinationStartingAtIndex(int[] source, int[] destination, int index) {
if (isIndexOfLastElementInArray(index, destination)) {
destination[index] = source[index];
} else {
destination[index] = source[index];
copyValuesFromSourceToDestinationStartingAtIndex(source, destination, index + 1);
}
}
static boolean isIndexOfLastElementInArray(int index, int[] array){
return index == array.length - 1;
}
To copy one array to another you can use either iteration or recursion. There is no need to do both. By this I mean there is no need for the for loop inside the rekursiq method.
The method getPeakCount takes an int array and a range (int) as an input and returns the number of integers that are greater than all the elements to either side for the given range.
For example, consider an array {1,4,2,6,4,5,10,8,7,11} and range 2. The result should be 3, as {..,4,2,6,4,5,..}, {..,4,5,10,8,7,..} and {..,8,7,11} satisfy this condition. These satisfy the condition because 6, 10 and 11 are all greater than the 2 elements to both their left and right.
Note that for the the corner elements like 1 and 11, there's no need to check the left and right side respectively.
My code is below, but it is not correct.
static int getPeakCount(int[] arr, int R) {
int result=0;
for(int i=0;i<arr.length;i++){
if(i==0){
if(arr[i]>arr[i+1]&&arr[i]>arr[i+2]){
result++;
}
} //-----> closing if(i==0) condition
else if(i==arr.length-1){
if(arr[i]>arr[i-1]&&arr[i]>arr[i-2]){
result++;
}
}
else if(i+R>arr.length){
if(arr[i]>arr[i-R] && arr[i]>arr[i-R+1]){
System.out.println(arr[i]);
result++;
}
}
else{
if(arr[i]>arr[i+1] && arr[i]>arr[i+2] && arr[i]>arr[i-R] && arr[i]>arr[i-R+1]){
System.out.println(arr[i]);
result++;
}
}
}
return result;
}
I don't know whether I'm going in the right direction or not, and for last if condition it's throwing an java.lang.ArrayIndexOutOfBoundsException.
P.S. Don't consider this code as solution to remove errors from this. This is just the attempt I tried.
I think the right idea, and devnull is right. You just need to check the center, so change the loop to start at 1 and end 1 before the end. I commented out the end conditions. I think this does what you were asking, though not 100% sure I understood what you were after.
I should add, I use variables like l (left), r (right) and c (center) for clarity. You can make this much faster if you have large arrays. There is also redundancy in that it checks conditions it should know are already false (if I find a peak, I should skip the next value, as it can't also be a peak).
public class PeakChecker {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
int[] array = new int[]{1, 4, 2, 6, 4, 5, 10, 8, 7, 11};
System.out.println(nPeaks(array, 2));
}
static int nPeaks(int[] array, int range) {
// Check for special cases
if (array == null) {
return 0;
}
int result = 0, l, r;
// Check main body
for (int i = 0; i < array.length; i++) {
boolean isPeak = true;
// Check from left to right
l = Math.max(0, i - range);
r = Math.min(array.length - 1, i + range);
for (int j = l; j <= r; j++) {
// Skip if we are on current
if (i == j) {
continue;
}
if (array[i] < array[j]) {
isPeak = false;
break;
}
}
if (isPeak) {
System.out.println("Peak at " + i + " = " + array[i]);
result++;
i += range;
}
}
return result;
}
}
The last if condition shall throw exception when i == arr.length - 2.
This is because arr[i+2] in that case is out of bounds.
If you read the ArrayIndexOutOfBoundsException stack trace, it will tell you a line of code the error happened on. Look on that line of code and you'll probably see arr[i+1] or arr[i-1] or something. Certainly, at least one access on that line will be out of bounds. That's the problem.
public static void what(int[] arr, int i)
{
if (i == 0)
return;
arr[arr.length - i] = i;
i--;
what(arr, i); // recursive method call
}
What I have here doesn't change anything, the array stays the same and a[i] doesn't = i. My logic is way off, any help?
I did a previous code where I had to set elements in an int array to zero, clearing the array. I used that as a basis for this initialization as well.
If you want a[i] = i then change to this:
public static void what(int[] arr, int i)
{
if (i == 0)
return;
arr[arr.length - i] = arr.length - i;
i--;
what(arr, i); // recursive method call
}
is this what you need ?
public static void what (int[] arr, int i)
{
if (i == 0)
return;
arr[i-1] = i-1;
i--;
what(arr, i); // recursive method call
}
This method will always return an array of the following content.
int arr[] = {0, 1, 2, 3, ..., n-1};
Your input array may be something like this. That may be the reason of your results not changing.
Recursion is pointless in this case because you will need more code, including a cycle, to validate the second parameter rather to solve the task.
The best case scenario for int[] intArr = new int[]{43,56,24,745,32} is to call what(intArr, 5) and get int[]{5,4,3,2,1}
Ofcourse, we have the most obvious issue: what(intArr,4343) will lead us to java.lang.ArrayIndexOutOfBoundsException but it can be fixed with ease: if( i <= arr.length && i>0 ).
It will be much more interesting if we will pass random value between 0 and 5(intArr.length)
what(intArr,2) will result in int[]{43, 56, 24, 2, 1}. How will you handle this case? The only way I see is to loop through intArr from i+1 to intArr.length-1 and check if we already performed what(intArr,3), what(intArr,4) and what(intArr,5).
Each time you call your method, you will need to loop through i-1 elements and check if it was processed already.
I would prefer to use a regular function with a loop:
public static void what(int[] arr)
{
for(int i = 0; i<arr.length; i++){
arr[i] = arr.length-i;
}
}
I feel like it is more readable, easier to understand if you do it the other way, starting from the front.
private static void what( int[] arr, int i )
{
if( i >= arr.length )
return;
arr[i] = i;
what( arr, i + 1 );
}
Here is it running.
I would try calling the function like what(array,array.length):
public static void what(int[] arr, int i)
{
if ( i == 0 )
return;
arr[i] = i;
what(arr, i-1); // recursive method call
}