Minimum Adjustment Cost - java

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]);
}

Related

Adjacency matrix generator

My goal is to create an adjacency matrix generator (the only value elements can have is 0 or 1; it has to be symmetric, meaning element in [i][j] == element [j][i]) in Java.
I have some code, but the result is an nx5 matrix (if I establish n = 13, the resulting matrix is a 13x5 matrix). It is symmetric and the values of elements is bounded between 0-1, so that is not an issue. Another problem is I don't really know how to have an array without doubles, which is more of an aesthetical problem + ideally, the diagonal would be filled with "-" instead of zeroes, as it is now.
Random random = new Random();
double[][] array = new double[n][n];
for (int i = 0; i < array.length; i++)
{
for (int j = 0; j <= i; j++)
{
int x = random.nextInt(2);
array[i][j] = x;
if (i != j)
{
array[j][i] = x;
}
}
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
if (i == j || (i + j + 1) == n)
{
array[i][j] = 0;
}
}
}
for (double[] a : array)
{
System.out.println(Arrays.toString(a));
}
}

Improve Efficiency of Alog (Rotate Array to Left by n iterations)

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/

Element in the array such that the sum of the elements on its left is equal to the sum of the elements on its right

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);
}

2d array inside another array?

Is there anyway to make an array hold 2d array?
I want to somehow hold the value of matrixFinal based on what the user enters so I can later use it. I think I'd be able to do this if I can hold these values in an array but these are 2d arrays...
How would I go about doing this?
public class Driver {
public static void main(String[] args) {
int i, j, k, l ;
int sum = 0 ;
int matrixAColumnSize ;
int matrixARowSize ;
int raiseByPower ;
// Querying user
matrixARowSize = Tools.queryForInt("Enter the row size of Matrix A: ") ;
matrixAColumnSize = Tools.queryForInt("Enter the column size of Matrix A: ") ;
Tools.verifyMatrixSize(matrixAColumnSize, matrixARowSize) ; // Verification of matrix size 10x10 max
Tools.verifyMultiplication(matrixARowSize, matrixAColumnSize) ; // Verification of matrix size
raiseByPower = Tools.queryForInt("By what power would you like to raise the matrix? ") ;
Tools.verifyMatrixPower(raiseByPower) ; // Verification of power. ^6 max
//Making matrices
int matrixA[][] = new int[matrixARowSize][matrixAColumnSize] ;
int matrixFinal[][] = new int [matrixARowSize][matrixAColumnSize] ;
// Querying for elements of Matrix A
for (i = 0; i < matrixARowSize; i++) {
for (j = 0; j < matrixAColumnSize; j++) {
matrixA[i][j] = Tools.queryForInt("Enter element in Matrix A" + (i+1) + "," + (j+1) + " :" ) ; }}
// Multiplying matrices
if (raiseByPower == 1) {
for (i = 0; i < matrixARowSize; i++) {
for (j = 0; j < matrixAColumnSize; j++) {
matrixFinal[i][j] = matrixA[i][j] ;
}
}
} else if (raiseByPower == 2) {
for (i = 0; i < matrixARowSize; i++)
{
for (j = 0; j < matrixAColumnSize; j++)
{
for (k = 0; k < matrixARowSize; k++)
{
sum = sum + matrixA[i][j] * matrixA[i][j] ;
}
matrixFinal[i][j] = sum ;
sum = 0 ;
}
}
} else if (raiseByPower == 3) {
for (i = 0; i < matrixARowSize; i++)
{
for (j = 0; j < matrixAColumnSize; j++)
{
for (k = 0; k < matrixARowSize; k++)
{
sum += matrixA[i][j] * matrixA[i][j] * matrixA[i][j] ;
sum = 0 ;
}
matrixFinal[i][j] = sum ;
}
}
} else if (raiseByPower == 4) {
for (i = 0; i < matrixARowSize; i++)
{
for (j = 0; j < matrixAColumnSize; j++)
{
for (k = 0; k < matrixARowSize; k++)
{
sum += matrixA[i][j] * matrixA[i][j] * matrixA[i][j] * matrixA[i][j] ;
}
matrixFinal[i][j] = sum ;
sum = 0 ;
}
}} else if ( raiseByPower == 5) {
for (i = 0; i < matrixARowSize; i++)
{
for (j = 0; j < matrixAColumnSize; j++)
{
for (k = 0; k < matrixARowSize; k++)
{
sum += matrixA[i][j] * matrixA[i][j] * matrixA[i][j] * matrixA[i][j] * matrixA[i][j] ;
}
matrixFinal[i][j] = sum ;
sum = 0 ;
}
}
} else if ( raiseByPower == 6) {
for (i = 0; i < matrixARowSize; i++)
{
for (j = 0; j < matrixAColumnSize; j++)
{
for (k = 0; k < matrixARowSize; k++)
{
sum += matrixA[i][j] * matrixA[i][j] * matrixA[i][j] * matrixA[i][j] * matrixA[i][j] * matrixA[i][j] ;
}
matrixFinal[i][j] = sum ;
sum = 0 ;
}
}
}
System.out.println("Matrix A to the power of " + raiseByPower + " is: ") ;
for (i = 0; i < matrixARowSize; i++) {
for (j = 0; j < matrixAColumnSize; j++)
System.out.print(matrixFinal[i][j] + "\t") ;
System.out.println();
}
} }
You can nest arrays as much as you want so something like int[][][] is certainly possible, which is an array of 2d arrays.
Well, you already have an int[][] so you can make an
int[][][] container = new int[numberofmatrixes][matrixsize][matrixsize];
and then add your matrixA or matrixFinal:
container[index] = matrixA;
and get values from matrixA:
int a = container[index][index2][index3];
where before you would have used
int a = matrixA[index2][index3];
You treat the 'container' array like any other array so the first matrix would be added at container[0], the second at container[1] and so on. You have to remember which matrix is at what index yourself.
In C, a 2d array and a 1d array are the "same thing", in that they are all calculated offsets from some memory address (a pointer, p). For example, to get the 5th element of an int array on a 32-bit compiler, you'd multiple (5-1)x4 and add that to the address p, which is written as p[4] (assuming that the type of p is a pointer to int and int is a 4-byte word). In Java, if p is an array of int, then you can likewise access the 5th one via p[4].
In C, you can access a 2d array in much the same way, e.g. p[4][2]. For example, see: http://www.tutorialspoint.com/cprogramming/c_multi_dimensional_arrays.htm
The way it works in C is that the first number is multiplied by the size of the array in rows, then added to the second number, then multiplied by the element size. So p[4][2] is ((void*)p)+168 if the array is 10x10 and the "int" (aka word size) is 32 bits, i.e. it's the 42nd element.
Now to do a "two-dimensional array on an array" in Java is a little more complex, because the compiler doesn't do that math for you, but you can do it. Just make a class called Matrix, take rows & columns in the constructor, create the underlying 1-dimensional array, and have two methods called:
public T get(int row, int column)
put(int row, int column, T value)
etc.

min n-m so that whole array will be sorted

I was asked the below question in an interview:
Given an array of integers, write a method to find indices m and n such that
if you sorted elements m through n, the entire array would be sorted. Minimize
n-m. i.e. find smallest sequence.
find my answer below and please do comment on the solution. Thanks!!!
At last I have got a solution to the problem, please feel free to comment.
Lets take an example:
int a[] = {1,3,4,6,10,6,16,12,13,15,16,19,20,22,25}
Now if i will put this in to the graph (X-coordinate -> array index and Y-coordinate -> array's value) then the graph will look like as below:
Now if we see the graph there are two places where dip happens one is after 10 and another after 16. Now in the zig zag portion if we see the min value is 6 and max val is 16. So the portion which we should sort to make the whole array sorted is between (6,16). Please refer to the below image:
Now we can easily divide the array in to three part. And middle part the one which we want to sort so that the whole array will be sorted. Please provide your valuable inputs. I tried to explain to my label best, please let me know if i want to explain more. Waiting for valuable inputs.
The below code implements the above logic:
public void getMN(int[] a)
{
int min = Integer.MAX_VALUE; int max = Integer.MIN_VALUE;
for(int i=1; i<a.length; i++)
{
if(a[i]<a[i-1])
{
if(a[i-1] > max)
{
max = a[i-1];
}
if(a[i] < min)
{
min = a[i];
}
}
}
if(max == Integer.MIN_VALUE){System.out.println("Array already sorted!!!");}
int m =-1, n =-1;
for(int i=0; i<a.length; i++)
{
if(a[i]<=min)
{
m++;
}
else
{
m++;
break;
}
}
for(int i=a.length-1; i>=0; i--)
{
if(a[i]>=max)
{
n++;
}
else
{
n++;
break;
}
}
System.out.println(m +" : "+(a.length-1-n));
System.out.println(min +" : "+max);
}
It's easier to find the max value starting from the end of array:
public void FindMinSequenceToSort(int[] arr)
{
if(arr == null || arr.length == 0) return;
int m = 0, min = findMinVal(arr);
int n = arr.length - 1, max = findMaxVal(arr);
while(arr[m] < min)
{
m ++;
}
while(arr[n] > max)
{
n --;
}
System.out.println(m);
System.out.println(n);
}
private int findMinVal(int[] arr)
{
int min = Integer.MAX_VALUE;
for(int i = 1; i < arr.length; i++)
{
if(arr[i] < arr[i-1] && arr[i] < min)
{
min = arr[i];
}
}
return min;
}
private int findMaxVal(int[] arr)
{
int max = Integer.MIN_VALUE;
for(int i = arr.length - 2; i >= 0; i--)
{
if(arr[i] >= arr[i+1] && arr[i] > max)
{
max = arr[i];
}
}
return max;
}
Actually, I came up with something like that:
public static void sortMthroughN(int[] a)
{
int m = -1;
int n = -1;
int k = -1;
int l = -1;
int biggest;
int smallest;
// Loop through to find the start of the unsorted array.
for(int i = 0; i < a.length-1; i++)
if(a[i] > a[i+1]) {
m = i;
break;
}
// Loop back through to find the end of the unsorted array.
for(int i = a.length-2; i > 0; i--)
if(a[i] > a[i+1]) {
n = i;
break;
}
biggest = smallest = a[m];
// Find the biggest and the smallest integers in the unsorted array.
for(int i = m+1; i < n+1; i++) {
if(a[i] < smallest)
smallest = a[i];
if(a[i] > biggest)
biggest = a[i];
}
// Now, let's find the right places of the biggest and smallest integers.
for(int i = n; i < a.length-1; i++)
if(a[i+1] >= biggest) {
k = i+1; //1
break;
}
for(int i = m; i > 0; i--)
if(a[i-1] <= smallest) {
l = i-1; //2
break;
}
// After finding the right places of the biggest and the smallest integers
// in the unsorted array, these indices is going to be the m and n.
System.out.println("Start indice: " + l);
System.out.println("End indice: " + k);
}
But, I see that results are not the same with your solution #Trying, did i misunderstand the question? By the way, at the and of your code, it prints
4 : 9
6 : 16
What are these? Which ones are indices?
Thanks.
EDIT: by adding place marked as 1 this:
if(a[i+1] == biggest) {
k = i;
break;
}
and 2:
if(a[i+1] == smallest) {
l = i;
break;
}
it is better.
Actually, you can have two pointers and the last pointer moves backward to check start index of the shortest unsorted sequence. It's kind of O(N2) but it is more cleaner.
public static int[] findMinUnsortedSequence(int[] array) {
int firstStartIndex = 0;
int startIndex = 0;
int endIndex = 0;
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < i; j++) {
if (array[j] <= array[i]) {
startIndex = j + 1;
} else {
endIndex = i;
if (firstStartIndex == 0) {
firstStartIndex = startIndex;
}
}
}
}
return new int[]{firstStartIndex, endIndex};
}

Categories

Resources