Array left rotation in Java - java

Given an array of integers and a number, I need to perform left rotations on the array and return the updated array to be printed as a single line of space-separated integers.
I pass 7/9 checks, but some with large arrays fail because of time-out.
The time has to be <= 4 sec.
static int[] rotLeft(int[] a, int d) {
int x = 0;
while (x != d) {
int first = a[0];
int last = a[a.length - 1];
for (int i = 0; i < a.length - 1; i++) {
a[i] = a[i + 1];
if (i == a.length - 2)
a[a.length - 2] = last;
a[a.length - 1] = first;
}
x++;
}
return a;
}

you're rotating only one position at a time, it is very slow, it is better to shift elements to appropriate places, for example:
static int[] rotLeft(int[] a, int d) {
if (d == 0 || a == null || a.length == 0) {
return a;
}
int[] b = new int[a.length];
for (int i = 0; i < a.length; i++) {
b[i] = a[(i + d) % a.length];
}
return b;
}

There are two things you could apply to this problem to improve the runtime.
Ensure that d is less than a.length. If d is greater than a.length, then you are rotating elements past their original position and wasting cycles. An easy way to achieve this is with the modulus assignment operator (i.e., d %= a.length, which is equivalent to d = d % a.length).
Elements should be shifted by the whole distance we are rotating, rather than shifting by one space each time. This allows us to perform the entire operation is 1 action, instead of in d action(s).
Applying these two principles would give us the following code:
static int[] rotLeft(int[] a, int d) {
if (d < 0) {
d = a.length - (-d % a.length);
}
d %= a.length;
if (d == 0) {
return a;
}
int first = a[0];
int i = 0;
int position = 0;
while (i < a.length) {
a[position] = a[(position + d) % a.length];
position = (position + d) % a.length;
i++;
}
a[a.length - d] = first;
return a;
}

You make multiple passes, each time rotating by one place, which makes your program slow.
There are at least 3 approaches to improve your program:
allocate a new array and put elements in appropriate locations, instead of rotating in place
use a buffer to store d elements while rotating others in place
use a juggling algorithm https://www.google.com/amp/s/www.geeksforgeeks.org/array-rotation/amp/
The third option performs rotation in place.
It may be worthwhile to microbenchmark all 3 to compare the speed for different input sizes

Of course you can repeat the rotation d times as you did in your sample code. But much faster would be if you would calculate the shift and do it in one go:
import static java.lang.System.*;
static int[] rotLeft( int[] a, int d )
{
var len = a.length;
var shift = d % len;
var buffer = new int[len];
arraycopy( a, shift, buffer, 0, len - shift );
arraycopy( a, 0, buffer, len - shift, shift );
arraycopy( buffer, 0, a, 0, len );
return a;
}
Of course, instead of System.arraycopy() you can use a for-loop. If you are not forced to return a, you can omit the third call to arraycopy() and return buffer instead; this would leave the original array unchanged, too.
To output the array, try this:
var joiner = new StringJoiner( " " );
for( var v : a ) joiner.add( Integer.toString( v ) );
System.out.println( joiner.toString() );

For better performance, you should use the built-in array copy methods.
If you have to update the existing array, like your code is doing, I'd recommend doing it like this:
static int[] rotLeft(int[] a, int d) {
if (a == null || a.length <= 1)
return a; // nothing to rotate
int shift = (d % a.length + a.length) % a.length; // normalize d
if (shift == 0)
return a; // no or full rotation(s)
int[] t = Arrays.copyOfRange(a, 0, shift);
System.arraycopy(a, shift, a, 0, a.length - shift);
System.arraycopy(t, 0, a, a.length - shift, shift);
return a;
}
If the returned array must be different, like this other answers do, I'd do it like this:
static int[] rotLeft(int[] a, int d) {
if (a == null || a.length <= 1)
return Arrays.copyOf(a, a.length); // nothing to rotate
int shift = (d % a.length + a.length) % a.length; // normalize d
if (shift == 0)
return Arrays.copyOf(a, a.length); // no or full rotation(s)
int[] t = new int[a.length];
System.arraycopy(a, shift, t, 0, a.length - shift);
System.arraycopy(a, 0, t, a.length - shift, shift);
return t;
}
Both of the above solution allow d to exceed the size of the array, i.e. do more than a full rotation, and to use negative values, i.e. rotate right instead of left.
Test
System.out.println(Arrays.toString(rotLeft(new int[] { 1, 2, 3, 4, 5 }, 1)));
System.out.println(Arrays.toString(rotLeft(new int[] { 1, 2, 3, 4, 5 }, 3)));
System.out.println(Arrays.toString(rotLeft(new int[] { 1, 2, 3, 4, 5 }, 5)));
System.out.println(Arrays.toString(rotLeft(new int[] { 1, 2, 3, 4, 5 }, 7)));
System.out.println(Arrays.toString(rotLeft(new int[] { 1, 2, 3, 4, 5 }, -7)));
Output
[2, 3, 4, 5, 1]
[4, 5, 1, 2, 3]
[1, 2, 3, 4, 5]
[3, 4, 5, 1, 2]
[4, 5, 1, 2, 3]

You don't have to do the rotations one by one. If you rotate by d, the element at index i moves to index i - d when i >= d, and into index N + i - d when i < d. Makes sense?
int[] result = new int[a.length]
for (int i = 0; i < a.length; i++) {
if (i < d) {
result[a.length + i - d] = a[i];
} else {
result[i - d] = a[i];
}
}
return result;
To handle the case where d >= a.length, you can add d = d % a.length as a pre-processing step.

Related

How to shift everything in a 2D array to the left

I need to take a 2D array and move everything as far left as possible. It is a 4x4 array and I have tried to do it but either only move certain items or the index goes out of bounds.
The gameBoard array looks like this:
{0 2 4 2}
{0 0 2 0}
{2 2 0 0}
{0 4 0 2}
and after you call the swipeLeft() method it should look like this:
{2 4 2 0}
{2 0 0 0}
{2 2 0 0}
{4 2 0 0}
There is also the issue of placing a zero into the previous index that you moved it from.
I created a double for loop to just loop through the array and tried to code something that would move it over but it hasn't worked.
Here was the code I had so far
public void swipeLeft() {
for ( int r = 0; r < gameBoard.length; r++ ) {
for ( int c = 0; c < gameBoard[r].length; c++ ) {
gameBoard[r][c] = gameBoard[r][ (c+1) %
gameBoard.length];
}
}
}
Based on your desired OUTPUT, it looks like swipeLeft() is supposed to push all non-zero values to the very left of their row, displacing the zeroes to the right of all non-zero values.
If that's correct, this is similar to Old Dog Programmer's approach, except all shifting is done "in place" without creating any new arrays:
import java.util.*;
class Main {
private static int[][] gameBoard;
public static void main(String[] args) {
gameBoard = new int[][] {
{0, 2, 4, 2},
{0, 0, 2, 0},
{2, 2, 0, 0},
{0, 4, 0, 2}
};
System.out.println("Before:");
displayBoard();
swipeLeft();
System.out.println("\nAfter:");
displayBoard();
}
public static void displayBoard() {
for(int[] row : gameBoard) {
System.out.println(Arrays.toString(row));
}
}
public static void swipeLeft() {
for(int[] row : gameBoard) {
// find the first blank (zero) spot
int nextIndex = 0;
while(nextIndex < row.length && row[nextIndex] != 0) {
nextIndex++;
}
// start with the first blank, and shift any non-zero
// values afterwards to the left
for(int col=nextIndex; col < row.length; col++) {
if (row[col] != 0) {
row[nextIndex] = row[col];
row[col] = 0;
nextIndex++;
}
}
}
}
}
Output:
Before:
[0, 2, 4, 2]
[0, 0, 2, 0]
[2, 2, 0, 0]
[0, 4, 0, 2]
After:
[2, 4, 2, 0]
[2, 0, 0, 0]
[2, 2, 0, 0]
[4, 2, 0, 0]
From the example in the question, it appears to me that what is wanted is to shift all non-zero elements to the left, and zero elements are shifted to the right. The order of the non-zero elements is to be retained.
Note that each row is independent of other rows.
One way to approach this is to create a method that works on a 1D array. This method takes a 1D array as a parameter, and returns another 1D array with the elements shifted:
public static int [] zeroShift (int [] arr) {
int [] left = new int [arr.length];
int count = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] != 0) {
left [count++] = arr [i];
}
}
return left;
}
This copies each non-zero element to a new array of the same size, keeping track (count) of how many have been copied so far. Note this relies on left being initialized to all-zeros.
Once that method is working, it can be used for gameBoard on a row-by-row basis:
public void swipeLeft() {
for (int r = 0; r < gameBoard.length; r++) {
gameBoard [r] = zeroShift (gameBoard [r]);
}
// output for testing
for (int i = 0; i < gameBoard.length; ++i) {
System.out.println(Arrays.toString(gameBoard[i]));
}
}
To rotate the array in place, you should roteate the array 3 times:
123456 -> 654312
654321
3456..
....12
public static void shiftLeft(int[] arr, int offs) {
if (offs <= 0)
return;
offs = arr.length - offs % arr.length - 1;
for (int i = 0, j = arr.length - 1; i < j; i++, j--)
swap(arr, i, j);
for (int i = 0, j = offs; i < j; i++, j--)
swap(arr, i, j);
for (int i = offs + 1, j = arr.length - 1; i < j; i++, j--)
swap(arr, i, j);
}
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
So your code intends to rotate the board one column to the left. Rotate? Well, the numbers you push out on the left might come back on the end, right?
Probably the line
gameBoard[r][c] = gameBoard[r][ (c+1) % gameBoard.length];
should be
gameBoard[r][c] = gameBoard[r][ (c+1) % gameBoard[r].length];
But try to do this stuff with pen & paper, and you should notice that you are going to loose one column/copy the values from the second column into the first, then copy that into the last column again.
You will need to change two items:
store the value from the first column somewhere if you still need it so you can push it into the last one.
only rotate the column data if it needs to be rotated. Or in other words, rotate the remainder of the row if you find a zero. In this case you do not need to remember the first column, as you will overwrite a zero and push a zero into the last column. And then it would not be called rotate but shift.
Exercise this with pen & paper until you can write down instructions for someone else to perform the same operation. Then you are ready to also write it in Java.

Counting triplets with smaller sum

I was trying one problem to count the number of triplets in an array whose sum is less than target value.
Input: [-1, 4, 2, 1, 3], target=5
Output: 4
Explanation: There are four triplets whose sum is less than the target:
[-1, 1, 4], [-1, 1, 3], [-1, 1, 2], [-1, 2, 3]
My Code
import java.util.*;
class TripletWithSmallerSum {
public static int searchTriplets(int[] arr, int target) {
Arrays.sort(arr);
int count = 0;
for(int i = 0; i < arr.length - 2; i++)
{
int left = i + 1;
int right = arr.length - 1;
while(left < right)
{
int targetDiff = target - arr[i] - arr[left] - arr[right];
if (targetDiff > 0)
{
count++;
right--;
}
else
{
left++;
}
}
}
// TODO: Write your code here
return count;
}
}
It produces the output of 3 where as correct value should be 4 as per the above given input. My logic was , say , x + y + z < targetSum , it implies (targetSum - (x + y + z) ) > 0. If this is true I will increase the count and then decrement the right pointer , since array is sorted. If its not true then I will increment the left pointer . But my logic does not cover the triplet {-1, 2, 3}.
Below is the correct code given by author.
import java.util.*;
class TripletWithSmallerSum {
public static int searchTriplets(int[] arr, int target) {
Arrays.sort(arr);
int count = 0;
for (int i = 0; i < arr.length - 2; i++) {
count += searchPair(arr, target - arr[i], i);
}
return count;
}
private static int searchPair(int[] arr, int targetSum, int first) {
int count = 0;
int left = first + 1, right = arr.length - 1;
while (left < right) {
if (arr[left] + arr[right] < targetSum) {
count += right - left;
left++;
} else {
right--; // we need a pair with a smaller sum
}
}
return count;
}
public static void main(String[] args) {
System.out.println(TripletWithSmallerSum.searchTriplets(new int[] { -1, 0, 2, 3 }, 3));
System.out.println(TripletWithSmallerSum.searchTriplets(new int[] { -1, 4, 2, 1, 3 }, 5));
}
}
The author has used the concept , say x + y + z < targetSum , it implies x + y < targetSum - z . But I don't get the logic of line count += right - left; . How author use this one line to capture the count. If some one can give me the intution on how to reach this inference. Also what is wrong with my code and what can I do to correct it.
A first issue with your code is that :
you only decrease the right index if the sum is inferior to the target.
However, since you have ordered your list, well you will only be entering that case until left=right.
Quick example : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], target=14
if 1+2+10 <13:
then you will only decrease 10 until you reach 2 in your array
and then you proceed to iterate to the next i-index, here going from 0 to 1.
Meaning that: you will never get the solutions in between such as [1,3,9] and all the one that follows.
I hope it helps you see where there was an error in the logic, which was not from the statement : (targetSum - (x + y + z) ) > 0 but from the action you take according to the result (True/False).
Now, I am not sure there would be an easy way to adapt your code corrctly, because the main issue here is that you have iterate over 2 indexes at once (right and left).
Now regarding your author's answer :
The trick behind :
count += right - left;
goes back to the issue you had, if i tame my example, for
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
it is basically saying that, since the array is ordered, if the sum of two integers with the right one is inferior to target, then it will also be true for all integers inferior to right :
1+2+10<14 => 1+2+9<13
And this statement is true for all integers between left and right, so instead of doing a loop for which we already have the answer, he adds to count the differences between right and left, in other words, the number of integers in your array that will be greater than left and lower than right.
Now that i have explained that, you could use the same "trick" to your code:
class TripletWithSmallerSum {
public static int searchTriplets(int[] arr, int target) {
Arrays.sort(arr);
int count = 0;
for(int i = 0; i < arr.length - 2; i++)
{
int left = i + 1;
int right = arr.length - 1;
while(left < right)
{
int targetDiff = target -( arr[i] + arr[left] + arr[right]);
if (targetDiff > 0)
{
count += right - left;
left++;
}
else
{
right--;
}
}
}
// TODO: Write your code here
return count;
}
}
I tried to be as detailed as possible, hope it helps you understand better!

Print SubArray of Maximum Contiguous product in Array

Maximum Product Subarray
Given an array that contains both positive and negative integers, find the subarray of the maximum product .
Examples:
Input: arr[] = {6, -3, -10, 0, 2}
Output: The subarray is {6, -3, -10}
Input: arr[] = {-1, -3, -10, 0, 60}
Output: The subarray is {60}
Input: arr[] = {-2, -3, 0, -2, -40}
Output: The subarray is {-2, -40}
Note: Finding the Max Product is done as using the kadane algo where i tried to reuse it for finding sub array but not able to break the part of finding the start index, finding end index is easy. end index is where res < max.
public int maxProductSubArray(int arr[], int len) {
int res = arr[0];
int max = arr[0];
int min = arr[0];
for (int i = 1; i < len; i++) {
int temp = max;
max = Math.max(Math.max(max * arr[i], min * arr[i]), arr[i]);
min = Math.min(Math.min(temp * arr[i], min * arr[i]), arr[i]);
res = Math.max(res, max);
}
return res;
}
but not able to break the problem to find the SubArray.
There are several possible ways to solve this problem:
Brute-Force
Divide-and-Conquer
Backtracking
I will only show you the Brute-Force-Solution. It is not the fastest solution, but in my opinion the most clear and easily understandable solution:
public class SubArray {
public static int findMax(int[] num) {
int max = num[0];
int start = 0;
int end = 0;
for(int i = 0; i < num.length; i++) { //Iterating over every possible starting position
for(int j = i; j < num.length; j++) { //Iterating over every possible end position
int multiply = 1;
for(int k = i; k <= j; k++) { //Multiply from start to end
multiply *= num[k];
}
if(max < multiply) { //Did we find a new maximum?
max = multiply;
start = i;
end = j;
}
}
}
System.out.print("The subarray is {"); //Print subarray with highest product
for(int i = start; i <= end; i++) {
System.out.print(num[i]);
if(i < end) {
System.out.print(", ");
}
}
System.out.println("}");
return max;
}
public static void main(String[] args) {
int[] array = {6, -3, -10, 0, 2} ;
int max = findMax(array);
System.out.println("Maximal product is: " + max);
}
}
This problem can be efficiently solved by divide and conquer.
Assume you want to solve the problem for a subarray [l, r]; Then, assuming c = (l + r) / 2 the solution is either subarray in [l, c], or in [c + 1, r], or in some subarray containing c and c + 1.
Then let's define a function f(l, r) returning the answer for subsegment; Then, to compute this function, first recursively call f(l, c) and f(c + 1, r) and pick the maximum as the temporary answer. Then compute multiplications of segments [c, c], then [c - 1, c] and so on (using multiplication of [c - k, c] = multiplication of [c - k + 1, c] * array[c - k]) and compute maximum and minimum multiplications across all such segments. Do the same for segments to the right of c ([c + 1, c + 1], [c + 1, c + 2] and so on) Then, the answer will be either a temporary answer, of multiplication of maximums or multiplication of minimums or multiplication of minimum and maximum and vice versa (minimum times maximum is required if such multiplication would be negative). Return the maximum across these four values or the temporary answer as the function result.
If it is necessary, instead of returning just the value of multiplication function can also return the segment where these value is reached.
This solution uses Θ(n log n) time and Θ(n) space.

Array overrides array in ArrayList

I want to save all the int[] data in my array list so i can see every thing step by step. Only my problem is that it overrides the already existing int[] in my ArrayList.
how can i fill my array list without overriding my old int in the ArrayList?
ArrayList<int[]> lijstje = new ArrayList<int[]>();
public int[] data = {7,4,8,56,67,85,23,65,23,65,23,22};
int stemp;
int len = 10;
public void shellSort(){
while (h <= len / 3) {
h = h * 3 + 1;
}
while (h > 0) {
for (outer = h; outer < len; outer++) {
stemp = data[outer];
inner = outer;
while (inner > h - 1 && data[inner - h] >= stemp) {
data[inner] = data[inner - h];
inner -= h;
}
data[inner] = stemp;
lijstje.add(data);
}
h = (h - 1) / 3;
}
}
Arrays are stored as references, so when you change the array one place, anywhere else you directly stored it will change to. Instead, make a brand new array with the same values, and store that. To do that, do array.clone(), so for you
ArrayList<int[]> lijstje = new ArrayList<int[]>();
public int[] data = {7,4,8,56,67,85,23,65,23,65,23,22};
int stemp;
int len = 10;
public void shellSort(){
while (h <= len / 3) {
h = h * 3 + 1;
}
while (h > 0) {
for (outer = h; outer < len; outer++) {
stemp = data[outer];
inner = outer;
while (inner > h - 1 && data[inner - h] >= stemp) {
data[inner] = data[inner - h];
inner -= h;
}
data[inner] = stemp;
lijstje.add(data.clone()); // Notice here how it's data.clone() instead of just data
}
h = (h - 1) / 3;
}
}
Here's an example showing how arrays are passed by referencing, this
int[] original = { 1, 2, 3 };
int[] passedByReference = original;
int[] cloned = original.clone();
System.out.println("Before:");
System.out.println(Arrays.toString(original));
System.out.println(Arrays.toString(passedByReference));
System.out.println(Arrays.toString(cloned));
original[0]=10;
System.out.println("After:");
System.out.println(Arrays.toString(original));
System.out.println(Arrays.toString(passedByReference));
System.out.println(Arrays.toString(cloned));
will have the following output
Before:
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
After:
[10, 2, 3]
[10, 2, 3]
[1, 2, 3]
as you can see, the cloned one is not affected, whereas the original and passed-by-reference ones are. In your code, you don't want changes to the original to affect the array you store, so you must clone it some way (array.clone() is a nice simple way for a 2D array).

Maximum distance between two different element in an array

I have a problem where I need to find the maximum distance between two different elements in an array.
For example: given an array 4,6,2,2,6,6,4 , the method should return 5 as the max distance.
I am able to solve the problem using two for loops but it is not an optimized solution. Am trying to optimize it by doing it in a single for loop.
here is my current solution:
int [] A = {4,6,2,2,6,6,4};
int N = A.length;
int result = 0;
for (int i = 0; i < N; i++){
for (int j = i; j < N; j++) {
if(A[i] != A[j]){
result = Math.max(result, j - i);
}
}
}
// tried below code but it is not efficient
// for (int i = 0; i < N; i++){
//
// if(A[N-1] != A[i]){
// result = Math.max(result, N-1-i);
// }
// }
System.out.println(result);
How to make this better in terms of time complexity?
Simple (not nested) loop is enough, but two cases should be taken into
account: either the best result is
4,6,2,2,6,6,4
^ ^ - moving first
or
4,6,2,2,6,6,4
^ ^ - moving last
for instance: [4, 2, 4, 4, 4] moving first brings the answer, when in case of [4, 4, 4, 2, 4] moving last should be used.
int first = 0;
int last = A.length - 1;
// 1st case: moving "first"
while (first < last) {
if (A[first] == A[last])
first++;
else
break;
}
int diff1 = last - first;
first = 0;
last = A.length - 1;
// 2nd case: moving "last"
while (first < last) {
if (A[first] == A[last])
last--;
else
break;
}
int diff2 = last - first;
// result is the max between two cases
int result = diff1 > diff2
? diff1
: diff2;
So we have O(N) time complexity.
Edit: Let's proof that at least one of the indexes is either 0 or length - 1. Let's do it by contradiction. Suppose we have a solution like
a, b, c, .... d, e, f, g
^ ..... ^ <- solution indexes (no borders)
Items to the left of c must be d, otherwise we can take a or b indexes and have an improved solution. Items to right of d must be c or we can once again push last index to the right and have a better solution. So we have
d, d, c .... d, c, c, c
^ .... ^ <- solution indexes
Now, since d <> c (c..d is a solution) we can improve the solution into
d, d, c .... d, c, c, c
^ .... ^ <- solution indexes
^ .... ^ <- better solution
We have a contradiction (the supposed solution is not one - we have a better choice) and that's why at least one index must be 0 or length - 1.
Now we have 2 scenarions to test:
a, b, ..... y, z
^ ...... ^ <- moving first
^ ...... ^ <- moving last
We can combine both conditions into if and have just one loop:
int result = 0;
for (int i = 0; i < A.length; ++i)
if (A[i] != A[A.length - 1] || A[0] != A[A.length - 1 - i]) {
result = A.length - i - 1;
break;
}
This can be done in a single loop
Consider this.
The maximum difference between from a index i can be either between start element and i or i and the last element
int main() {
vector<int> v {4, 6, 2, 2, 6, 6, 4};
int start = 0, end = v.size() -1;
int result = 0;
for(int i=0; i< v.size(); ++i)
{
if(v[i] != v[start])
{
result = max(result, i);
}
if(v[i] != v[end])
{
result = max(result, end - i);
}
}
return result;
}
The reason we are able to achieve a O(N) algorithm is because
Consider v = [4, 4, 2, 3, 4, 4]
At index i = 0 we check if we can find the maximum possible distance i.e with the last element but since they are same we can't consider it.
At i = 0 for this array the maximum possible answer would have been 5.
[4, 4, 2, 3, 4, 4]
^
At i = 1 we again check both ends of the array still the same so we move on.
The real savings come here that we do not have to check for every other entry
keeping the start at i = 0
So, at i = 2, we find that the maximum can be obtained with the end of the array
[4, 4, 2, 3, 4, 4]
^ ^ ^
start i end
which is the same as keeping the start constant and keeping a runner loop.

Categories