Mergesort Algorithm in Java - java

I've tried to write a Mergesort Algorithm in Java:
static void merge(int[] sort, int l, int m, int r) {
int[] cache_array = new int[r - l + 1];
int l_cache = l;
int _mid = m + 1;
for (int i = 0; i < r - l + 1; i++) {
if (l > m) {
cache_array[i] = sort[_mid];
_mid++;
} else { if (_mid > r) {
cache_array[i] = sort[l];
l++;
} else { if (sort[l] >= sort[_mid]) {
cache_array[i] = sort[l];
l++;
} else { if (sort[_mid] > sort[l]) {
cache_array[i] = sort[_mid];
_mid++;
}}}}
}
for (int i = 0; i < cache_array.length; i++) {
sort[i + l_cache] = cache_array[i];
}
}
static void mergeSort(int[] sort, int l, int r) {
if (l < r) {
int mid = (int)Math.floor((l + r - 1) / 2);
mergeSort(sort, l, mid);
mergeSort(sort, mid + 1, r);
merge(sort, l, mid, r);
}
}
public static void main(String[] args) {
int[] a = { 2, 1, 4, 5, 73, 74, 7, 5, 64, 2 };
mergeSort(a, 0, a.length - 1);
for (int i : a) {
System.out.println(i);
}
}
But it just sorts a part of the Array and replaces the rest of it with zeros. I tried to change the cache_array to a LinkedList but nothing changed and after I tried debugging I couldn't find out anything, too.
I'd appreciate it if you'd help me and/or show me another Mergesort Algorithm that works for Java.
(I used this Algorithm because it worked for Python and so I wanted to use similar code in Java)

The bug in your code is difficult to spot:
the loop in your merge function iterates for i from 0 to r - l + 1 excluded, which would be correct if r and l remained constant during the loop, but you increment l each time you copy from the left part, reducing the number of iterations. As a consequence, the loop exits early, leaving the remaining elements in cache_array with their default value 0.
There are multiple sources of confusion in the code:
the convention to include r in the slice is confusing: it requires +1/-1 adjustments to compute the slice lengths and the middle index.
using Math.floor() is useless: integer arithmetic uses integer division in java.
incrementing the l and m arguments is confusing as these lose their meaning if the value is changed. Use other index variables to iterate through the arrays.
adding a { between the else and if keywords introduces unnecessary indentation levels.
the last condition is the opposite of the previous one: you should just omit it. Note that if the array elements were floating point values, both conditions could be false for NaN values and some elements of cache_array would be left untouched. This last condition would cause errors in this case.
Here is a modified version:
// merge adjacent slices of the `sort` array.
// left slice has elements from `l` included to `m` excluded
// right slice has elements from `m` included to `r` excluded
static void merge(int[] sort, int l, int m, int r) {
int len = r - l;
int[] cache_array = new int[len];
for (int i = 0, ll = l, mm = m; i < len; i++) {
if (ll >= m) {
cache_array[i] = sort[mm];
mm++;
} else
if (mm >= r) {
cache_array[i] = sort[ll];
ll++;
} else
if (sort[ll] >= sort[mm]) {
cache_array[i] = sort[ll];
ll++;
} else {
cache_array[i] = sort[mm];
mm++;
}
}
for (int i = 0; i < len; i++) {
sort[l + i] = cache_array[i];
}
}
static void mergeSort(int[] sort, int l, int r) {
if (r - l > 1) {
int mid = l + (r - l) / 2;
mergeSort(sort, l, mid);
mergeSort(sort, mid, r);
merge(sort, l, mid, r);
}
}
public static void main(String[] args) {
int[] a = { 2, 1, 4, 5, 73, 74, 7, 5, 64, 2 };
mergeSort(a, 0, a.length);
for (int i : a) {
System.out.println(i);
}
}

This is how I write the mergesort algorithm.
public static int[] mergeSort(int[] sort) {
if(sort.length > 1) {
int mid = sort.length / 2;
int[] left = Arrays.copyOf(sort, mid);
int[] right = Arrays.copyOfRange(sort, mid, sort.length);
// sort the left and right arrays
mergeSort(left);
mergeSort(right);
// Merge the arrays
merge(sort, left, right);
}
}
private static void merge(int[] sort, int[] leftArray, int[] rightArray) {
// These values are just to keep track of our position in each of the 3
// arrays
int l = 0; // left array
int r = 0; // right array
int o = 0; // the actual array being sorted
while(l < leftArray.length && r < rightArray.length) {
if(leftArray[l] < righArray[r]) {
sort[o++] = leftArray[l++];
}
else {
sort[o++] = leftArray[r++];
}
}
// Now that we are out of the while loop we know that either the
// left or right array has all of its values in sort, so we just
// need to put the rest of the values in the array that doesn't have
// all of its elements in sort with the following code.
while(l < leftArray.length) {
sort[o++] = leftArray[l++];
}
while(r < rightArray.length) {
sort[o++] = rightArray[r++];
}
}

I usually implement it like this:
/// <summary>
/// Mergesort
/// best-case: O(n* log(n))
/// average-case: O(n* log(n))
/// worst-case: O(n* log(n))
/// </summary>
/// <returns>The sorted array.</returns>
/// <param name="array">array.</param>
public static int[] MergeSort(int[] array) {
// Exit condition for recursion
if (array.length <= 1) return array;
// Middle index of list to sort
int m = array.length / 2;
// Define left and right sub-listså
int[] left_array = new int[m];
int[] right_array = new int[array.length - m];
// Initialize left list
for (int i = 0; i < m; i++) left_array[i] = array[i];
// Initialize right list
for (int i = m, x = 0; i < array.length; i++, x++) right_array[x] = array[i];
// Recursively sort left half of the list
left_array = MergeSort(left_array);
// Recursively sort right half of the list
right_array = MergeSort(right_array);
// Merge sorted sub-lists
return Merge(left_array, right_array);
}
/// <summary>
/// Merge the specified left_array and right_array.
/// </summary>
/// <returns>The merge.</returns>
/// <param name="left_array">Left array.</param>
/// <param name="right_array">Right array.</param>
public static int[] Merge(int[] left_array, int[] right_array) {
int[] m = new int[left_array.length + right_array.length];
int index_l = 0;
int nl, nr;
nl = left_array.length - 1;
nr = right_array.length - 1;
for (int i = 0; i <= nl + nr + 1; i++) {
if (index_l > nl) {
m[i] = (right_array[i - index_l]);
continue;
}
if (index_l < i - nr) {
m[i] = (left_array[index_l]);
index_l++;
continue;
}
if (left_array[index_l] <= (right_array[i - index_l])) {
m[i] = (left_array[index_l]);
index_l++;
} else {
m[i] = (right_array[i - index_l]);
}
}
return m;
}
A few months ago I wrote all of the common sorting algorithms and this is what I got. A bit inaccurate but just to See how this implementation performs.
The other algorithms are here.
To achieve a descending order I think you just have to swap the comparison operators.

Related

MergeSort Algorithm from largest to smallest in java

So I want to use the mergesort algorithm to sort an array filled with numbers from largest to smallest. I have working code for this but I can't seem to make it sort from largest to smallest. I tried playing around with the for loop that has all of those if statements in there but I just couldn't figure it out. Could someone please help.
public class MergeSorter
{
public void merge(int[] a, int l, int h) {
if (h <= l) return;
int result = (l + h) / 2;
merge(a, l, result);
merge(a, result + 1, h);
sort_descend(a, l, result, h);
}
public void sort_descend(int[] a, int l, int result, int h) {
int first_replace[] = new int[result - l + 1];
int second_replace[] = new int[h - result];
for (int i = 0; i < first_replace.length; i++)
first_replace[i] = a[l + i];
for (int i = 0; i < second_replace.length; i++)
second_replace[i] = a[result+ i + 1];
int first_i = 0;
int second_i = 0;
for (int i = l; i < h + 1; i++) {
if (first_i < first_replace.length && second_i < second_replace.length) {
if (first_replace[first_i] < second_replace[second_i]) {
a[i] = first_replace[first_i];
first_i++;
} else {
a[i] = second_replace[second_i];
second_i++;
}
} else if (first_i < first_replace.length) {
a[i] = first_replace[first_i];
first_i++;
} else if (second_i < second_replace.length) {
a[i] = second_replace[second_i];
second_i++;
}
}
}
}
import java.util.Arrays;
public class MergeSortTest
{
public static void main(String args[]) {
int[] array = new int[]{ 6, 1, 3, 8, 3, 9, 2 };
MergeSorter ms = new MergeSorter();
ms.merge(array, 0, array.length - 1);
System.out.println(Arrays.toString(array));
}
}
Your entire logic is correct except one thing. In the sort_descend function, after you copy the array a into first_replace and second_replace, you start comparing the elements using the if condition if (first_replace[first_i] < second_replace[second_i]).
Here, you essentially assign the smaller of the two elements into your array a and this the step which determines whether your array will be sorted in ascending order or descending order.
To sort in descending order, you need to just reverse this sign and you will get the desired output i.e. change the if condition to if (first_replace[first_i] > second_replace[second_i]).
Please refer to the below code to sort an array of integers in descending order.
It is similar to your solution but only one change of the comparator operator on line number 38.
import java.util.Arrays;
public class C
{
public static void main(String args[]) {
int[] array = new int[]{ 6, 1, 3, 8, 3, 9, 2 };
MergeSorter ms = new MergeSorter();
ms.merge(array, 0, array.length - 1);
System.out.println(Arrays.toString(array));
}
}
class MergeSorter {
public void merge(int[] a, int l, int h) {
if (h <= l) return;
int result = (l + h) / 2;
merge(a, l, result);
merge(a, result + 1, h);
sort_descend(a, l, result, h);
}
public void sort_descend(int[] a, int l, int result, int h) {
int first_replace[] = new int[result - l + 1];
int second_replace[] = new int[h - result];
for (int i = 0; i < first_replace.length; i++)
first_replace[i] = a[l + i];
for (int i = 0; i < second_replace.length; i++)
second_replace[i] = a[result + i + 1];
int first_i = 0;
int second_i = 0;
for (int i = l; i < h + 1; i++) {
if (first_i < first_replace.length && second_i < second_replace.length) {
if (first_replace[first_i] >= second_replace[second_i]) {
a[i] = first_replace[first_i];
first_i++;
} else {
a[i] = second_replace[second_i];
second_i++;
}
} else if (first_i < first_replace.length) {
a[i] = first_replace[first_i];
first_i++;
} else if (second_i < second_replace.length) {
a[i] = second_replace[second_i];
second_i++;
}
}
}
}

Java: Implementing Merge Sort

I want to implement Merge Sort using one a mergeSort method that splits the sequences of an int array up until it's a single element and using a method merge to put them together.
With my code as it is I get a Stackoverflow Error.
Anyone has an idea why?
public static int[] mergeSort(int[] seq) {
return mergeSort(seq, 0, seq.length - 1);
}
private static int[] mergeSort(int[] seq, int l, int r) {
if (seq.length < 2) {
return seq;
}
int s = (l + r) / 2;
int[] a = new int[s];
int[] b = new int[seq.length - s];
for (int i : a) {
a[i] = seq[i];
}
for (int j : b) {
b[j] = seq[s + j];
}
mergeSort(a);
mergeSort(b);
return merge(a, b);
}
public static int[] merge(int[] ls, int[] rs) {
// Store the result in this array
int[] result = new int[ls.length + rs.length];
int i, l, r;
i = l = r = 0;
while (i < result.length) {
if (l < ls.length && r < rs.length) {
if (ls[l] < rs[r]) {
result[i] = ls[l];
++i;
++l;
} else {
result[i] = rs[r];
++i;
++r;
}
} else if (l >= ls.length) {
while (r < rs.length) {
result[i] = rs[r];
++i;
++r;
}
} else if (r >= rs.length) {
while (l < ls.length) {
result[i] = ls[l];
++i;
++l;
}
}
}
return result;
}
The stack overflow is caused by calling the method recursively too many times, possibly infinitely.
private static int[] mergeSort(int[] seq, int l, int r) this will always be called with l=0 and r=seq.length-1, so it's not really necessary to overload.
Here: int s = (l + r) / 2; if the array has 2 elements, this will return 0 (l=0, r=1), so the array will be split to a length 0, and a length 2 (and here is what causes the infinite recursive calls). Add one to the result, and the splitting of the array will work correctly.
To copy the parts of the original array, it's easier to use Arrays.copyOfRange() than writing your own for loop. And you're trying to use the existing elements of arrays a and b, which will all be 0, for indexing.
There are two small issues with your code.
First one is here:
public static int[] mergeSort(int[] seq) {
return mergeSort(seq, 0, seq.length - 1);
}
You need to call it as return mergeSort(seq, 0, seq.length);
The reason behind that is that for example when you have 2 elements and you call it like that with -1 you pass an array with 2 elements but s=1+0/2 =0 and you don't actually split it. Each subsequent recursion call is done with one empty array and one array with the same 2 elements causing an infinite loop and a stackoverflow exception
The second problem is this one:
for (int i : a) { and for (int i : b) {
You can't do the for loop like because you want to iterate on indexes not values of the array. You need to change it to:
for (int i=0;i<a.length;i++) {
a[i] = seq[i];
}
for (int i=0;i<b.length;i++) {
b[i] = seq[s + i];
}
And the last problem with your code is that you don't assign the values of the resulting sorted array and when you do the recursive calls it returns the sorted sub part but you don't get the result. It should become:
a=mergeSort(a);
b=mergeSort(b);
And here is the final code:
public static void main(String... args) {
int[] array={3,9,4,5,1} ;
array=mergeSort(array);
for(int i:array) {
System.out.print(i+",");
}
}
private static int[] mergeSort(int[] seq) {
if (seq.length < 2) {
return seq;
}
int s = seq.length / 2; //You always use that value. no need for 2 methods
int[] a = new int[s];
int[] b = new int[seq.length - s];
for (int i=0;i<a.length;i++) {
a[i] = seq[i];
}
for (int i=0;i<b.length;i++) {
b[i] = seq[s + i];
}
a=mergeSort(a);
b=mergeSort(b);
return merge(a, b);
}
public static int[] merge(int[] ls, int[] rs) {
// Store the result in this array
int[] result = new int[ls.length + rs.length];
int i, l, r;
i = l = r = 0;
while (i < result.length) {
if (l < ls.length && r < rs.length) {
if (ls[l] < rs[r]) {
result[i] = ls[l];
++i;
++l;
} else {
result[i] = rs[r];
++i;
++r;
}
} else if (l >= ls.length) {
while (r < rs.length) {
result[i] = rs[r];
++i;
++r;
}
} else if (r >= rs.length) {
while (l < ls.length) {
result[i] = ls[l];
++i;
++l;
}
}
}
return result;
}

How can I use this for loop to correctly print the closest K integers to X?

public static int[] sortArray(int[] arr) {
Arrays.sort(arr);
return arr;
}
public static int findElement(int[] arr, int x) {
int start = 0;
int end = arr.length;
int mid = 0;
while (start <= end) {
mid = (start + end)/2;
if (arr[mid] == x) {
return x;
}
else if (x <= arr[mid]) {
end = mid - 1;
}
else {
start = mid + 1;
}
}
return mid;
}
public static void printKclosest(int arr[], int x, int k)
{
int element = findElement(arr, x);
int count = 0;
for (int i = 0; i < arr.length; i++) {
int difference = Math.abs(arr[i] - element);
while (count < k) {
if (difference > 0) {
System.out.println(arr[i]);
count++;
}
}
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
int[] array = {-1, 3, 5, 2, 1, 7};
sortArray(array);
System.out.println(Arrays.toString(array));
printKclosest(array, 2, 3);
}
}
for find the k nearest elements, i was thinking I could use a for loop to go through each element in the array and subtract from the element that's X and print the number of k elements that have the smallest difference, but the output I'm getting is -1 k amount of times.
function findElement returns x value if x exists but index of potential place for x if it does not present in array.
So in the second case your comparison int difference = Math.abs(arr[i] - element); has no sense
How to overcome: change in findElement
int end = arr.length - 1;
return x;
to
return mid;
and
difference = Math.abs(arr[i] - arr[element]);
But approach to get k closest numbers is completely wrong. Suggestion:
Set L index to element and R index to element+1
Compare abs differences for L and R. Output smaller. If smaller is for R, decrement L, otherwise increment R. Repeat k times (don't forget about array range)
In addition to MBo's great suggestion for outputting the k closest elements using L and R pointers, you could also solve this without sorting the array in O(n log k) time by iterating over the array once and keeping the chosen elements in a heap, each time removing the farthest (k+1)th element.

What part of my code is making my performance suffer? (Codility's MaxCounter)

I have the following problem:
You are given N counters, initially set to 0, and you have two possible operations on them:
increase(X) − counter X is increased by 1,
max counter − all counters are set to the maximum value of any counter.
A non-empty zero-indexed array A of M integers is given. This array represents consecutive operations:
if A[K] = X, such that 1 ≤ X ≤ N, then operation K is increase(X),
if A[K] = N + 1 then operation K is max counter.
For example, given integer N = 5 and array A such that:
A[0] = 3
A[1] = 4
A[2] = 4
A[3] = 6
A[4] = 1
A[5] = 4
A[6] = 4
the values of the counters after each consecutive operation will be:
(0, 0, 1, 0, 0)
(0, 0, 1, 1, 0)
(0, 0, 1, 2, 0)
(2, 2, 2, 2, 2)
(3, 2, 2, 2, 2)
(3, 2, 2, 3, 2)
(3, 2, 2, 4, 2)
The goal is to calculate the value of every counter after all operations.
Write a function:
class Solution { public int[] solution(int N, int[] A); }
that, given an integer N and a non-empty zero-indexed array A consisting of M integers, returns a sequence of integers representing the values of the counters.
For example, given:
A[0] = 3
A[1] = 4
A[2] = 4
A[3] = 6
A[4] = 1
A[5] = 4
A[6] = 4
the function should return [3, 2, 2, 4, 2], as explained above.
Assume that:
N and M are integers within the range [1..100,000];
each element of array A is an integer within the range [1..N + 1].
Complexity:
expected worst-case time complexity is O(N+M);
expected worst-case space complexity is O(N), beyond input storage (not counting the storage required for input arguments).
Elements of input arrays can be modified.
I have answered this problem using the following code, but only got 80% as opposed to 100% performance, despite having O(N+M) time complexity:
public class Solution {
public int[] solution(int N, int[] A) {
int highestCounter = N;
int minimumValue = 0;
int lastMinimumValue = 0;
int [] answer = new int[N];
for (int i = 0; i < A.length; i++) {
int currentCounter = A[i];
int answerEquivalent = currentCounter -1;
if(currentCounter >0 && currentCounter<=highestCounter){
answer[answerEquivalent] = answer[answerEquivalent]+1;
if(answer[answerEquivalent] > minimumValue){
minimumValue = answer[answerEquivalent];
}
}
if (currentCounter == highestCounter +1 && lastMinimumValue!=minimumValue){
lastMinimumValue = minimumValue;
Arrays.fill(answer, minimumValue);
}
}
return answer;
}
}
Where is my performance here suffering? The code gives the right answer, but does not perform up-to-spec despite having the right time complexity.
Instead of calling Arrays.fill(answer, minimumValue); whenever you encounter a "max counter" operation, which takes O(N), you should keep track of the last max value that was assigned due to "max counter" operation, and update the entire array just one time, after all the operations are processed. This would take O(N+M).
I changed the variables names from min to max to make it less confusing.
public class Solution {
public int[] solution(int N, int[] A) {
int highestCounter = N;
int maxValue = 0;
int lastMaxValue = 0;
int [] answer = new int[N];
for (int i = 0; i < A.length; i++) {
int currentCounter = A[i];
int answerEquivalent = currentCounter -1;
if(currentCounter >0 && currentCounter<=highestCounter){
if (answer[answerEquivalent] < lastMaxValue)
answer[answerEquivalent] = lastMaxValue +1;
else
answer[answerEquivalent] = answer[answerEquivalent]+1;
if(answer[answerEquivalent] > maxValue){
maxValue = answer[answerEquivalent];
}
}
if (currentCounter == highestCounter +1){
lastMaxValue = maxValue;
}
}
// update all the counters smaller than lastMaxValue
for (int i = 0; i < answer.length; i++) {
if (answer[i] < lastMaxValue)
answer[i] = lastMaxValue;
}
return answer;
}
}
The following operation is O(n) time:
Arrays.fill(answer, minimumValue);
Now, if you are given a test case where the max counter operation is repeated often (say n/3 of the total operations) - you got yourself an O(n*m) algorithm (worst case analysis), and NOT O(n+m).
You can optimize it to be done in O(n+m) time, by using an algorithm that initializes an array in O(1) every time this operation happens.
This will reduce worst case time complexity from O(n*m) to O(n+m)1
(1)Theoretically, using the same idea, it can even be done in O(m) - regardless of the size of the number of counters, but the first allocation of the arrays takes O(n) time in java
This is a bit like #Eran's solution but encapsulates the functionality in an object. Essentially - keep track of a max value and an atLeast value and let the object's functionality do the rest.
private static class MaxCounter {
// Current set of values.
final int[] a;
// Keeps track of the current max value.
int currentMax = 0;
// Min value. If a[i] < atLeast the a[i] should appear as atLeast.
int atLeast = 0;
public MaxCounter(int n) {
this.a = new int[n];
}
// Perform the defined op.
public void op(int k) {
// Values are one-based.
k -= 1;
if (k < a.length) {
// Increment.
inc(k);
} else {
// Set max
max(k);
}
}
// Increment.
private void inc(int k) {
// Get new value.
int v = get(k) + 1;
// Keep track of current max.
if (v > currentMax) {
currentMax = v;
}
// Set new value.
a[k] = v;
}
private int get(int k) {
// Returns eithe a[k] or atLeast.
int v = a[k];
return v < atLeast ? atLeast : v;
}
private void max(int k) {
// Record new max.
atLeast = currentMax;
}
public int[] solution() {
// Give them the solution.
int[] solution = new int[a.length];
for (int i = 0; i < a.length; i++) {
solution[i] = get(i);
}
return solution;
}
#Override
public String toString() {
StringBuilder s = new StringBuilder("[");
for (int i = 0; i < a.length; i++) {
s.append(get(i));
if (i < a.length - 1) {
s.append(",");
}
}
return s.append("]").toString();
}
}
public void test() {
System.out.println("Hello");
int[] p = new int[]{3, 4, 4, 6, 1, 4, 4};
MaxCounter mc = new MaxCounter(5);
for (int i = 0; i < p.length; i++) {
mc.op(p[i]);
System.out.println(mc);
}
int[] mine = mc.solution();
System.out.println("Solution = " + Arrays.toString(mine));
}
My solution: 100\100
class Solution
{
public int maxCounterValue;
public int[] Counters;
public void Increase(int position)
{
position = position - 1;
Counters[position]++;
if (Counters[position] > maxCounterValue)
maxCounterValue = Counters[position];
}
public void SetMaxCounter()
{
for (int i = 0; i < Counters.Length; i++)
{
Counters[i] = maxCounterValue;
}
}
public int[] solution(int N, int[] A)
{
if (N < 1 || N > 100000) return null;
if (A.Length < 1) return null;
int nlusOne = N + 1;
Counters = new int[N];
int x;
for (int i = 0; i < A.Length; i++)
{
x = A[i];
if (x > 0 && x <= N)
{
Increase(x);
}
if (x == nlusOne && maxCounterValue > 0) // this used for all maxCounter values in array. Reduces addition loops
SetMaxCounter();
if (x > nlusOne)
return null;
}
return Counters;
}
}
( #molbdnilo : +1 !) As this is just an algorithm test, there's no sense getting too wordy about variables. "answerEquivalent" for a zero-based array index adjustment? Gimme a break ! Just answer[A[i] - 1] will do.
Test says to assume A values always lie between 1 and N+1. So checking for this is not needed.
fillArray(.) is an O(N) process which is within an O(M) process. This makes the whole code into an O(M*N) process when the max complexity desired is O(M+N).
The only way to achieve this is to only carry forward the current max value of the counters. This allows you to always save the correct max counter value when A[i] is N+1. The latter value is a sort of baseline value for all increments afterwards. After all A values are actioned, those counters which were never incremented via array entries can then be brought up to the all-counters baseline via a second for loop of complexity O(N).
Look at Eran's solution.
This is how we can eliminate O(N*M) complexity.
In this solutions, instead of populating result array for every A[K]=N+1, I tried to keep what is min value of all elements, and update result array once all operation has been completed.
If there is increase operation then updating that position :
if (counter[x - 1] < minVal) {
counter[x - 1] = minVal + 1;
} else {
counter[x - 1]++;
}
And keep track of minVal for each element of result array.
Here is complete solution:
public int[] solution(int N, int[] A) {
int minVal = -1;
int maxCount = -1;
int[] counter = new int[N];
for (int i = 0; i < A.length; i++) {
int x = A[i];
if (x > 0 && x <= N) {
if (counter[x - 1] < minVal) {
counter[x - 1] = minVal + 1;
} else {
counter[x - 1]++;
}
if (maxCount < counter[x - 1]) {
maxCount = counter[x - 1];
}
}
if (x == N + 1 && maxCount > 0) {
minVal = maxCount;
}
}
for (int i = 0; i < counter.length; i++) {
if (counter[i] < minVal) {
counter[i] = minVal;
}
}
return counter;
}
This is my swift 3 solution (100/100)
public func solution(_ N : Int, _ A : inout [Int]) -> [Int] {
var counters = Array(repeating: 0, count: N)
var _max = 0
var _min = 0
for i in A {
if counters.count >= i {
let temp = max(counters[i-1] + 1, _min + 1)
_max = max(temp, _max)
counters[i-1] = temp
} else {
_min = _max
}
}
return counters.map { max($0, _min) }
}

Java - Rotating array

So the goal is to rotate the elements in an array right a times.
As an example; if a==2, then array = {0,1,2,3,4} would become array = {3,4,0,1,2}
Here's what I have:
for (int x = 0; x <= array.length-1; x++){
array[x+a] = array[x];
}
However, this fails to account for when [x+a] is greater than the length of the array. I read that I should store the ones that are greater in a different Array but seeing as a is variable I'm not sure that's the best solution.
Thanks in advance.
Add a modulo array length to your code:
// create a newArray before of the same size as array
// copy
for(int x = 0; x <= array.length-1; x++){
newArray[(x+a) % array.length ] = array[x];
}
You should also create a new Array to copy to, so you do not overwrite values, that you'll need later on.
In case you don't want to reinvent the wheel (maybe it's an exercise but it can be good to know), you can use Collections.rotate.
Be aware that it requires an array of objects, not primitive data type (otherwise you'll swap arrays themselves in the list).
Integer[] arr = {0,1,2,3,4};
Collections.rotate(Arrays.asList(arr), 2);
System.out.println(Arrays.toString(arr)); //[3, 4, 0, 1, 2]
Arraycopy is an expensive operation, both time and memory wise.
Following would be an efficient way to rotate array without using extra space (unlike the accepted answer where a new array is created of the same size).
public void rotate(int[] nums, int k) { // k = 2
k %= nums.length;
// {0,1,2,3,4}
reverse(nums, 0, nums.length - 1); // Reverse the whole Array
// {4,3,2,1,0}
reverse(nums, 0, k - 1); // Reverse first part (4,3 -> 3,4)
// {3,4,2,1,0}
reverse(nums, k, nums.length - 1); //Reverse second part (2,1,0 -> 0,1,2)
// {3,4,0,1,2}
}
public void reverse(int[] nums, int start, int end) {
while (start < end) {
int temp = nums[start];
nums[start] = nums[end];
nums[end] = temp;
start++;
end--;
}
}
Another way is copying with System.arraycopy.
int[] temp = new int[array.length];
System.arraycopy(array, 0, temp, a, array.length - a);
System.arraycopy(array, array.length-a, temp, 0, a);
I think the fastest way would be using System.arrayCopy() which is native method:
int[] tmp = new int[a];
System.arraycopy(array, array.length - a, tmp, 0, a);
System.arraycopy(array, 0, array, a, array.length - a);
System.arraycopy(tmp, 0, array, 0, a);
It also reuses existing array. It may be beneficial in some cases.
And the last benefit is the temporary array size is less than original array. So you can reduce memory usage when a is small.
Time Complexity = O(n)
Space Complexity = O(1)
The algorithm starts with the first element of the array (newValue) and places it at its position after the rotation (newIndex). The element that was at the newIndex becomes oldValue. After that, oldValue and newValue are swapped.
This procedure repeats length times.
The algorithm basically bounces around the array placing each element at its new position.
unsigned int computeIndex(unsigned int len, unsigned int oldIndex, unsigned int times) {
unsigned int rot = times % len;
unsigned int forward = len - rot;
// return (oldIndex + rot) % len; // rotating to the right
return (oldIndex + forward) % len; // rotating to the left
}
void fastArrayRotation(unsigned short *arr, unsigned int len, unsigned int rotation) {
unsigned int times = rotation % len, oldIndex, newIndex, length = len;
unsigned int setIndex = 0;
unsigned short newValue, oldValue, tmp;
if (times == 0) {
return;
}
while (length > 0) {
oldIndex = setIndex;
newValue = arr[oldIndex];
while (1) {
newIndex = computeIndex(len, oldIndex, times);
oldValue = arr[newIndex];
arr[newIndex] = newValue;
length--;
if (newIndex == setIndex) { // if the set has ended (loop detected)
break;
}
tmp = newValue;
newValue = oldValue;
oldValue = tmp;
oldIndex = newIndex;
}
setIndex++;
}
}
int[] rotate(int[] array, int r) {
final int[] out = new int[array.length];
for (int i = 0; i < array.length; i++) {
out[i] = (i < r - 1) ? array[(i + r) % array.length] : array[(i + r) % array.length];
}
return out;
}
The following rotate method will behave exactly the same as the rotate method from the Collections class used in combination with the subList method from the List interface, i.e. rotate (n, fromIndex, toIndex, dist) where n is an array of ints will give the same result as Collections.rotate (Arrays.asList (n).subList (fromIndex, toIndex), dist) where n is an array of Integers.
First create a swap method:
public static void swap (int[] n, int i, int j){
int tmp = n[i];
n[i] = n[j];
n[j] = tmp;
}
Then create the rotate method:
public static void rotate (int[] n, int fromIndex, int toIndex,
int dist){
if(fromIndex > toIndex)
throw new IllegalArgumentException ("fromIndex (" +
fromIndex + ") > toIndex (" + toIndex + ")");
if (fromIndex < toIndex){
int region = toIndex - fromIndex;
int index;
for (int i = 0; i < dist % region + ((dist < 0) ? region : 0);
i++){
index = toIndex - 1;
while (index > fromIndex)
swap (n, index, --index);
}
}
}
Java solution wrapped in a method:
public static int[] rotate(final int[] array, final int rIndex) {
if (array == null || array.length <= 1) {
return new int[0];
}
final int[] result = new int[array.length];
final int arrayLength = array.length;
for (int i = 0; i < arrayLength; i++) {
int nIndex = (i + rIndex) % arrayLength;
result[nIndex] = array[i];
}
return result;
}
For Left Rotate its very simple
Take the difference between length of the array and number of position to shift.
For Example
int k = 2;
int n = 5;
int diff = n - k;
int[] array = {1, 2, 3, 4, 5};
int[] result = new int[array.length];
System.arraycopy(array, 0, result, diff, k);
System.arraycopy(array, k, result, 0, diff);
// print the output
Question : https://www.hackerrank.com/challenges/ctci-array-left-rotation
Solution :
This is how I tried arrayLeftRotation method with complexity o(n)
looping once from k index to (length-1 )
2nd time for 0 to kth index
public static int[] arrayLeftRotation(int[] a, int n, int k) {
int[] resultArray = new int[n];
int arrayIndex = 0;
//first n-k indexes will be populated in this loop
for(int i = k ; i
resultArray[arrayIndex] = a[i];
arrayIndex++;
}
// 2nd k indexes will be populated in this loop
for(int j=arrayIndex ; j<(arrayIndex+k); j++){
resultArray[j]=a[j-(n-k)];
}
return resultArray;
}
package com.array.orderstatistics;
import java.util.Scanner;
public class ArrayRotation {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int r = scan.nextInt();
int[] a = new int[n];
int[] b = new int[n];
for (int i = 0; i < n; i++) {
a[i] = scan.nextInt();
}
scan.close();
if (r % n == 0) {
printOriginalArray(a);
} else {
r = r % n;
for (int i = 0; i < n; i++) {
b[i] = a[(i + r) < n ? (i + r) : ((i + r) - n)];
System.out.print(b[i] + " ");
}
}
}
private static void printOriginalArray(int[] a) {
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
}
}
Following routine rotates an array in java:
public static int[] rotateArray(int[] array, int k){
int to_move = k % array.length;
if(to_move == 0)
return array;
for(int i=0; i< to_move; i++){
int temp = array[array.length-1];
int j=array.length-1;
while(j > 0){
array[j] = array[--j];
}
array[0] = temp;
}
return array;
}
You can do something like below
class Solution {
public void rotate(int[] nums, int k) {
if (k==0) return;
if (nums == null || nums.length == 0) return;
for(int i=0;i<k;i++){
int j=nums.length-1;
int temp = nums[j];
for(;j>0;j--){
nums[j] = nums[j-1];
}
nums[0] = temp;
}
}
}
In the above solution, k is the number of times you want your array to rotate from left to right.
Question : Rotate array given a specific distance .
Method 1 :
Turn the int array to ArrayList. Then use Collections.rotate(list,distance).
class test1 {
public static void main(String[] args) {
int[] a = { 1, 2, 3, 4, 5, 6 };
List<Integer> list = Arrays.stream(a).boxed().collect(Collectors.toList());
Collections.rotate(list, 3);
System.out.println(list);//[4, 5, 6, 1, 2, 3]
}// main
}
I use this, just loop it a times
public void rotate(int[] arr) {
int temp = arr[arr.length - 1];
for(int i = arr.length - 1; i > 0; i--) {
arr[i] = arr[i - 1];
}
arr[0] = temp;
}

Categories