I am solving a challenge to rotate array to left by n number of iterations.
Code is pretty much working but lags on very very huge input.
How to more improve efficiency
// Complete the rotLeft function below.
static int[] rotLeft(int[] a, int iterations) {
for(int i=0;i<iterations;i++)
{
int[] temp=Arrays.copyOfRange(a, 1, a.length);
temp=Arrays.copyOf(temp,a.length);
temp[a.length-1]=a[0];
a=temp;
}
return a;
}
Suggestions are welcome.
Thanks
Instead on shifting iterations you can calculate the final position directly.
finalIndex=(index-iterations+a.length) % a.length
+a.length is added to ensure that the finalIndex is always a not negattive value.
If you apply this to your algorithm, you get rid of the loop and do the whole thing in one step.
This reduced time complexity of the algorithm from O(a.length*iterations) to O(a.length).
There are few flaws in the code.
First, you do redundant work - if iterations > a.length - then after a.length iterations the array just returns back to itself.
Second, each iteration creates a whole new copy of the array!
Third, the new location of each element in the array can be predetermined by looking only on the array length, the number of iterations required, and the index of this element, no need to repeatidly go over iterations.
When taking these into considerations, this can boil down to something in the form of:
static int[] rotLeftEfficient(int[] a, int iterations) {
iterations = iterations % a.length;
int[] b = new int[a.length];
for (int i = 0; i < a.length; i++) {
int newIndex = (i - iterations + a.length) % a.length;
b[newIndex] = a[i];
}
return b;
}
This boils down to O(n) solution - where n is the number of elements in the array, with decent constants as well.
Here is a rotate in place (doesn't use a second array), with O(a.length) time complexity. On my system (Intel 3770K 3.5ghz), it can rotate a 2^28 = 268,435,456 element array in .17 (rotate 76) to .85 seconds (rotate 1). The swaps are done in sequential access sequences, which is cache friendly.
// rotate in place
public static void rolip(int[] a, int r){
r = r % a.length;
if(r == 0)
return;
int t;
int n = a.length - r;
int i = 0;
int j;
while(true){
if(r <= n){ // shift left r places
for(j = i+r; i < j; i++){
t = a[i]; // swap(a[i], a[i+r])
a[i] = a[i+r];
a[i+r] = t;
}
n -= r;
if(n == 0)
break;
} else { // shift right n places
i += r;
for(j = i+n; i < j; i++){
t = a[i]; // swap(a[i], a[i-n])
a[i] = a[i-n];
a[i-n] = t;
}
i -= n+r;
r -= n;
if(r == 0)
break;
}
}
}
Simple rotate using a second array. On my system (Intel 3770K 3.5ghz), it can rotate a 2^28 = 268,435,456 element array in .11 to .50 seconds.
public static void rol(int[] a, int r){
r = r % a.length;
if(r == 0)
return;
int n = a.length - r;
int i;
int j;
if(r <= n){ // if left rotate
int[] b = new int[r]; // save elements
for(j = 0; j < r; j++)
b[j] = a[j];
for(i = 0; i < n; i++) // shift elements
a[i] = a[j++];
for(j = 0; j < r; j++) // copy saved elements
a[i++] = b[j];
} else { // else right rotate
int[] b = new int[n]; // save elements
i = 0;
for(j = r; j < a.length; j++)
b[i++] = a[j];
i = j-1; // shift elements
for(j = i-n; j >= 0; j--)
a[i--] = a[j];
for(j = 0; j < n; j++) // copy saved elements
a[j] = b[j];
}
}
You don't need to do it for every iteration. Instead you can create a formula to figure out where every element would go.
For example, let's say that the size of your array is n.
Then, if you need to move your array to the left by 1 iteration, then an element at position p would be at (p + 1) % n position.
For i iterations, every element would be at (p + i) % n location. So, a loop for every iteration is not needed.
static int[] rotLeft(int[] a, int iterations) {
int[] answer = new int[a.length];
for(int i=0;i<a.length;i++)
{
answer[i] = a[(i - iterations + a.length) % (a.length)];
}
return answer;
}
What about this:
static int leftRotate(int arr[], int iterations,
int k)
{
/* To get the starting point of
rotated array */
int mod = k % iterations;
// Prints the rotated array from
// start position
for(int i = 0; i < iterations; ++i)
System.out.print(arr[(i + mod) % iterations]
+ " ");
System.out.println();
}
leftRotate(arr, iterations, arr.length);
Ref: https://www.geeksforgeeks.org/print-left-rotation-array/
Related
I have trouble saving each step of sorting quickstep. I wrote this but its not printing anything...
I want to make javafx application with feature that i can push next button and it makes one step and back button which goes step back. So i will run the whole quicksort and save all the iterations to matrix and later i will be showing each column of the matrix bz clicking next and back. So i wanted to strat from beginning but im stuck in saving the steps.
Edit:
P.S. I know should print the matrix each step and i dont want that, i will add some condition later.
public class QS {
public static void main(String[] args) {
int[] x = { 9, 2, 4, 7, 3, 7, 10 };
System.out.println(Arrays.toString(x));
final int [] [] test = {
{1,2,3},
{4,5,6},
{7,8,9}
};
//for (int p = 0; p < test.length; p++){
// for (int k = 0; k < test[p].length; k++){
// System.out.print(test[p][k] + " ");
// }
// System.out.println();
//}
int low = 0;
int high = x.length - 1;
quickSort(x, low, high);
System.out.println(Arrays.toString(x));
int [] [] save = new int [9] [x.length];
}
public static void quickSort(int[] arr, int low, int high) {
if (arr == null || arr.length == 0)
return;
if (low >= high)
return;
// pick the pivot
int middle = low + (high - low) / 2;
int pivot = arr[middle];
// make left < pivot and right > pivot
int i = low, j = high;
while (i <= j) {
while (arr[i] < pivot)
i++;
while (arr[j] > pivot)
j--;
if (i <= j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i++;
j--;
}
}
int[][] save = new int[9][arr.length];
int index = 0;
// recursively sort two sub parts
if (low < j)
quickSort(arr, low, j);
for (int h=0; h>arr.length+1; h++){
save [index] [h] = arr [h];
index++;
for (int e = 0; e < save.length; e++) {
for (int f = 0; f < save[e].length; f++) {
System.out.print(save[e][f] + " ");
}
System.out.println();
}
}
if (high > i)
quickSort(arr, i, high);
for (int h=0; h>arr.length+1; h++){
save [index] [h] = arr [h];
index++;
for (int e = 0; e < save.length; e++) {
for (int f = 0; f < save[e].length; f++) {
System.out.print(save[e][f] + " ");
}
System.out.println();
}
}
}
}
In the for loops like this one:
for (int h=0; h>arr.length+1; h++){/*code*/}
Presumably, it should be a smaller-than sign:
for (int h=0; h<arr.length+1; h++){/*code*/}
Otherwise h is always bigger than arr.length+1, making the condition false and and the loop just stops there.
I am trying to solve this question:
Given an integer array, adjust each integers so that the difference of
every adjacent integers are not greater than a given number target.
If the array before adjustment is A, the array after adjustment is B,
you should minimize the sum of `| A[i]-B[i] |. You can assume each number in the array is a positive integer and not greater than 100.
`
I see a dp solution but I don't quite understand the recurrence equation.
public static int MinAdjustmentCost(ArrayList<Integer> A, int target) {
// write your code here
if (A == null || A.size() == 0) {
return 0;
}
// D[i][v]: 把index = i的值修改为v,所需要的最小花费
int[][] D = new int[A.size()][101];
int size = A.size();
for (int i = 0; i < size; i++) {
for (int j = 1; j <= 100; j++) {
D[i][j] = Integer.MAX_VALUE;
if (i == 0) {
// The first element.
D[i][j] = Math.abs(j - A.get(i));
} else {
for (int k = 1; k <= 100; k++) {
// 不符合条件
if (Math.abs(j - k) > target) {
continue;
}
int dif = Math.abs(j - A.get(i)) + D[i - 1][k];
D[i][j] = Math.min(D[i][j], dif);
}
}
}
}
int ret = Integer.MAX_VALUE;
for (int i = 1; i <= 100; i++) {
ret = Math.min(ret, D[size - 1][i]);
}
return ret;
}
Could someone explain it to me?
You need to minimize the cost of the adjustment, which is the value you increase/decrease every element such that the difference between every adjacent elements is less than or equal to target. The dp solution is to try every possible value and minimize the cost on the valid ones (when abs(A[i]-A[i-1]) <= target)
First thing is to fill the cost for adjusting first element to 1-100 which is done here:
for (int i = 0; i < size; i++) {
for (int j = 1; j <= 100; j++) {
D[i][j] = Integer.MAX_VALUE; // fill with MAX_VALUE because we want to minimize
if (i == 0) {
// for the first element we just set the cost of adjusting A[i] to j
D[i][j] = Math.abs(j - A.get(i));
}
Now you have D[0][j] as the cost to adjust the first element to be j. Then for every other element, you loop again (from k = 1 to k = 100) for other elements and try to change A[i] to j. And then you check if abs(k-j) is valid (less than or equal to target) then you can adjust A[i] to be j and A[i-1] to be k so you minimize on D[i][j].
Here D[i][j] means the cost of changing A[i] to j and D[i-1][k] is the cost of changing A[i-1] to k. so for every k and j if they are valid (abs(k-j)<=target) then you add them together and minimize the value saved in D[i][j] so you can use it for next element, which is done here:
else {
for (int k = 1; k <= 100; k++) {
// if abs(j-k) > target then changing A[i] to j isn't valid (when A[i-1] is k)
if (Math.abs(j - k) > target) {
continue;
}
// otherwise, calculate the the cost of changing A[i] to j and add to it the cost of changing A[i-1] to k
int dif = Math.abs(j - A.get(i)) + D[i - 1][k];
// minimize D[i][j]
D[i][j] = Math.min(D[i][j], dif);
}
}
At the end, you need to loop from 1 to 100 at the last element and check which is the minimum value over all, which is done here:
int ret = Integer.MAX_VALUE;
for (int i = 1; i <= 100; i++) {
ret = Math.min(ret, D[size - 1][i]);
}
I think if you split the initialization code and the DP calculation code it would be easier to understand, for example:
// fill the initial values
for (int i = 0; i < size; ++i) {
for (int j = 1; j <= 100; ++j) {
// on the first element just save the cost of changing
// A[i] to j
if (i == 0) {
DP[i][j] = abs(j-A.get(i));
} else {
// otherwise intialize with MAX_VALUE
D[i][j] = Integer.MAX_VALUE;
}
}
}
for (int i = 1; i < size; i++) {
for (int j = 1; j <= 100; j++) {
for (int k = 1; k <= 100; k++) {
// if abs(j-k) isn't valid skip it
if (Math.abs(j - k) > target) {
continue;
}
// if it is valid, calculate the cost of changing A[i] to j
// and add it to the cost of changing A[i-1] to k then minimize
// over all values of j and k
int dif = Math.abs(j - A.get(i)) + D[i - 1][k];
D[i][j] = Math.min(D[i][j], dif);
}
}
}
// calculate the minimum cost at the end
int ret = Integer.MAX_VALUE;
for (int i = 1; i <= 100; i++) {
ret = Math.min(ret, D[size - 1][i]);
}
private static int f(int[] a, int low, int high)
{
int res = 0;
for (int i = low; i <= high; i++)
res += a[i];
return res;
}
/**
*
* #return the size of the largest gap in the array in which the combined values contained in the indexes are divisible by 3
*
*/
public static int what(int[] a)
{
int temp = 0;
for (int i = 0; i < a.length; i++)
{
for (int j = i; j < a.length; j++)
{
int c = f(a, i, j);
if (c % 3 == 0)
{
if (j - i + 1 > temp)
temp = j - i + 1;
}
}
}
return temp;
}
I need to calculate the algorithmic complexity of what. I think it might be n^2 because it has two loops, but it could also be n^3 because it uses f which has another loop. How can I determine its algorithmic complexity?
I am trying to solve Sherlock and Array algorithm task. I have array and i need to find element in the array such that the sum of the elements on its left side is equal to the elements of it's right side, like i mentioned in the title. My algorithm works for small arrays, but for big arrays it is too slove, what can i do to improve it's speed ?
Just to mention. This algorithm dont accept arrays of size 1 and 2.
public static boolean isSherlock(int arr[])
{
int length = arr.length;
int leftSum = 0;
int rightSum = 0;
for(int i=0; i<length-1; i++)
{
leftSum = 0;
rightSum = 0;
// Left sum for index i
for(int j=0; j<i; j++)
leftSum+=arr[j];
// Right sum for index i
for(int j=i+1; j<length && leftSum != 0; j++)
rightSum+=arr[j];
if(leftSum == rightSum && leftSum != 0 && rightSum != 0)
{
return true;
}
}
return false;
}
This is O(N^2) is there any way to do it in O(n) ?
The linear solution is pretty easy.
Calculate the sum of all elements in the array A. Of course, it can be done in linear time. Call it S.
Then iterate over all elements and store two sums: the sum of all elements which lie to the left on the current element and the sum of all elements which lie to the right on the current elements. Call them L and R.
For the first element A[0]:
L = 0
R = S - A[0]
When you move to A[i] you recalculate L and R:
L = L + A[i - 1]
R = R - A[i]
If L == R then the current elements is the answer.
At, first store the sum and then use that sum. Here is the code below:
public static boolean isSherlock(int arr[])
{
int length = arr.length;
int sum = 0;
for(int i=0; i<length; ++i)
sum += arr[i];
int rightSum = sum-arr[0];
int leftSum = 0;
for(int i=0; i<length-1; ++i){
if(leftSum == rightSum)
return true;
leftSum += arr[i];
rightSum -= arr[i+1];
}
if (leftSum == rightSum)
return true;
return false;
}
You could save the left sum and rigth sum computed at previous step as follows:
int sumLeftStepI=0;
int sumRigthStepI = Arrays.stream(a).sum() - a[0];
for (int i=0; i<a.length;i++){
if(sumLeftStepI==sumRigthStepI){
System.out.println("found element at position a["+i+"]");
}
if(i<a.length-1){
sumLeftStepI+=a[i];
sumRigthStepI-=a[i+1];
}
}
In this way the complexity should be O(n).
try this
public static boolean isSherlock(int arr[])
{
if (arr.length > 2) {
int i = 1;
for (; i < arr.length - 1; i++) {
int k = 0;
int rhs = arr[i + 1];
int lhs = arr[i - 1];
int j = arr.length - 1;
// **In single iteration it is suming from left as well as from right**
while (k < i - 1 && j > i + 1) {
rhs += arr[j--];
lhs += arr[k++];
}
// **************
// If any elements remain
while (k < i - 1)
lhs += arr[k++];
while (j > i + 1)
rhs += arr[j--];
// compare
if (rhs == lhs && lhs != 0 && rhs != 0) {
return true;
}
}
}
return false;
}
No need to create a separate variable for sum. Assign the sum value to the right or the left.
This is the most efficient code that I came up with.
Also it is obvious that for array of length less than 3, result would
always be false.
private static boolean balanceIntArrray(int[] nums) {
int length = nums.length;
if (length < 3) {
return false;
}
int left = nums[0];
int right = 0;
for (int i = 2; i < nums.length; i++) {
right += nums[i];
}
for (int i = 1; i < nums.length - 1; i++) {
if (left == right) {
return true;
}
left += nums[i];
right -= nums[i + 1];
}
return (left == right);
}
public int[][] Solution(int[][] matrix, int flag) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return matrix;
//int m = matrix.length, n = matrix[0].length;
int[][] rvalue;
rvalue = transpose(matrix);
flip(rvalue, flag);
return rvalue;
}
// transporse the matrix
private int[][] transpose(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
int[][] rvalue = new int[n][m];
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
rvalue[i][j] = matrix[j][i];
return rvalue;
}
// clockwise rotate the matrix
private void flip(int[][] matrix, int flag) {
int m = matrix.length, n = matrix[0].length;
if (flag == 1) {
for (int i = 0; i < m; i++)
for (int j = 0; j < n / 2; j++) {
matrix[i][j] ^= matrix[i][n-j-1]; // line 1
matrix[i][n-j-1] ^= matrix[i][j]; // line 2
matrix[i][j] ^= matrix[i][n-j-1]; // line 3
}
}
}
Above is the code for rotating the matrix (first transporse, then rotate). But I cannot understand the code for line 1,2 and 3, I replaced these three lines with my own following code and it works well.
int temp=matrix[i][j];
matrix[i][j]=matrix[i][matrix[0].length-j-1];
matrix[i][matrix[0].length-j-1]=temp;
Can someone explain what the original three lines doing?
The 3 lines are using the xor operator to exchange values.
I would never use it unless you really are hard pressed for memory because, as you obviously noticed, it's very hard to understand.
Here's a link to some info on the algorithm it's using to exchange the values