I am calculating the index of an n dimensional array transformed to a flat 1d array.
private int toFlatindex(int... dimensionIndices){
int index = 0;
for (int k = dimensionIndices.length - 1; k >= 0; k--) {
// Check if the specified index is within the bounds of the array
if(dimensionIndices[k] < 0 || dimensionIndices[k] >= dimensionSizes[k]) {
return -1;
}
// get the index in the flat array using the formula from https://en.wikipedia.org/wiki/Row-major_order#Address_calculation_in_general
int start = 1;
for (int l = dimensionSizes.length - 1; l >= k+1; l--) {
start = start * dimensionSizes[l];
}
index += dimensionIndices[k]*start;
}
return index;
}
I have written this code which appears and tests correct. Although I have coded the formula from wikipedia I don't fully understand what is happening. I would appreciate someone explaining this, or even better linking a video tutorial/lecture on the address calculation.
Let's work through the first few dimensions manually.
For a 1d array, which is a single row, element [k] is at position k.
For a 2d array, element [j,k] specifies the k'th element of row j. This is k + start of row j. The start of row j is at j * number of columns. If the dimensions are listed in the array dimensionSize, then the number of columns is dimensionSize[0].
Putting this together, element [j,k] is at dimensionSize[0] * j + k.
For a 3d array, element [i,j,k] specifies the k'th element of row j within "plane" i of the cube of elements. This is k + start of row j in plane i. The start of row j in plane i is i * size of plane + j * size of row. Putting this together, element [i,j,k] is at
dimensionSize[0] * dimensionSize[1] * i + dimensionSize[0] * j + k.
Another way of writing this is
dimensionSize[0] * (dimensionSize[1] * i + j) + k.
The pattern is emerging. If we had a 4d array, element [h,i,j,k] would be
dimensionSize[0] * (dimensionSize[1] * (dimensionSize[2] * h + i) + j) + k
Now replace the indices k,j,i,h with an array dimensionIndices[0..3] and you should be able to see that function is doing this computation for an arbitrary number of dimensions.
A simpler coding would be:
int getOffset(int [] sizes, int [] indices) {
int ofs = indices[sizes.length - 1];
for (int d = sizes.length - 2; d >= 0; --d) {
ofs = ofs * sizes[d] + indices[d];
}
return ofs;
}
Related
I'm having a hard time figuring out how to fill my 2D array with random numbers without duplicates. I currently have it filed with random numbers within the correct range, but I just cant think of a solution to have non duplicates. How could i do this using very basic java methods? I have not yet learned anything such as arraylists, or anything like that, only the very basic methods.
Given a MxN integer array, you could fill the array with numbers from 1 to M*N using two for-loops, and then swap them using the Fisher-Yates algorithm.
EDIT:
I changed the algorithm so that it now does not create a new integer-array every time the algorithm is called. It uses one loop, and calculates m, n, i j from a random value and the iterating varaible l. Assuming the given array is not null, rectangular and at least 1x0 in size:
public static void fillRandomlyUniqe(int[][] a) {
/*
fill up the array with incrementing values
if the values should start at another value, change here
*/
int value = 1;
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[i].length; j++)
a[i][j] = value++;
}
// swap them using Fisher-Yates algorithm
Random r = new Random();
int max = a.length * a[0].length;
for (int l = max - 1; l > 0; l--) {
//calculate a two dimensional index from random number
int index = r.nextInt(l + 1);
int m = index % a.length;
int n = index / a.length;
//calculate two dimensional index from the iterating value
int i = l % a.length;
int j = l / a.length;
int temp = a[i][j];
a[i][j] = a[m][n];
a[m][n] = temp;
}
}
If your 2D array is NxM, and you want numbers from (say) 1 to NxM randomly placed in your 2D array, the simplest is to create an array/list with the numbers from 1 to NxM, shuffle it, then fill in your 2D array sequentially from the shuffled data. You are guaranteed to not have any duplicates because the original non-shuffled data is full of unique values.
List<Integer> data = IntStream.rangeClosed(1, M * N).boxed().collect(Collectors.toList());
Collections.shuffle(data);
Iterator<Integer> iter = data.iterator();
for (int i = 0; i < M; i++) {
for (int j = 0; j < N; j++) {
array[i][j] = iter.next();
}
}
There is probably a way to do the second half with the stream API too, but it escapes me at the moment.
I am working on a project that requires finding some smaller 2d int arrays contained within a larger 2d int array.
To be more specific, I will be provided with a text file for input. The text file will contain an N, M, and K value, as well as integers to populate a "large" MxN grid. I will then need to find all "small" KxK grids within that larger MxN grid, and return the largest int within each KxK grid.
So, for example:
m = 3; n = 4; k = 2
MxN:
3 4 2
2 3 1
8 3 2
7 8 1
The 1st KxK grid to analyze would be:
3 4
2 3
return 4;
The 2nd:
4 2
3 1
return 4;
The 3rd:
2 3
8 3
return 8;
etc, etc.
Is there a slick way of iterating through these KxK grids with the mod operator or something? I feel like there is a simple solution for this, but it's not obvious to me.
I know this is more of a math problem than a programming one, but any help would be appreciated.
Thanks.
I've tried to write little code here:
private int[] getMaxFromGrids(int k, int[][] yourArray){
int m = yourArray.length; //height of grid
int n = yourArray[0].length; //width of grid, assuming that all inner array have same length!
//argument k is size of smaller grid
//computing max possibilities to fit smaller grid to larger one
int maxPossibilities = (m - k + 1) * (n - k + 1);
if(maxPossibilities < 1 || k < 1) return null;
int[] maxValuesSmallGrid = new int[maxPossibilities];
for (int i = 0; i < (maxPossibilities); i++) {
//computing actual start element for small grid
int colStartElement = i % (n - (k - 1));
int rowStartElement = i / (n - (k - 1));
//creating smaller grid
int[] smallGrid = new int[k * k];
int o = 0; //index of smaller grid
for (int j = colStartElement; j < colStartElement + k; j++) {
for (int l = rowStartElement; l < rowStartElement + k; l++) {
smallGrid[o++] = yourArray[j][l];
}
}
maxValuesSmallGrid[i] = getMax(smallGrid);
}
return maxValuesSmallGrid;
}
//method for getting max number from given array
private int getMax(int[] numbers) {
int max = Integer.MIN_VALUE;
for(int num : numbers) {
if(num > max) max = num;
}
return max;
}
Given that K<=N && K<=M, you can easily find all subarray2d by moving their top left corner from 0,0 to N-K,M-K (use 2 for loops)
Then make a function taking the coordinates of the top left corner of a K*K subarray2d and returning its higher value :)
I'm trying to solve the edit distance problem. the code I've been using is below.
public static int minDistance(String word1, String word2) {
int len1 = word1.length();
int len2 = word2.length();
// len1+1, len2+1, because finally return dp[len1][len2]
int[][] dp = new int[len1 + 1][len2 + 1];
for (int i = 0; i <= len1; i++) {
dp[i][0] = i;
}
for (int j = 0; j <= len2; j++) {
dp[0][j] = j;
}
//iterate though, and check last char
for (int i = 0; i < len1; i++) {
char c1 = word1.charAt(i);
for (int j = 0; j < len2; j++) {
char c2 = word2.charAt(j);
//if last two chars equal
if (c1 == c2) {
//update dp value for +1 length
dp[i + 1][j + 1] = dp[i][j];
} else {
int replace = dp[i][j] + 1 ;
int insert = dp[i][j + 1] + 1 ;
int delete = dp[i + 1][j] + 1 ;
int min = replace > insert ? insert : replace;
min = delete > min ? min : delete;
dp[i + 1][j + 1] = min;
}
}
}
return dp[len1][len2];
}
It's a DP approach. The problem it since it use a 2D array we cant solve this problem using above method for large strings. Ex: String length > 100000.
So Is there anyway to modify this algorithm to overcome that difficulty ?
NOTE:
The above code will accurately solve the Edit Distance problem for small strings. (which has length below 1000 or near)
As you can see in the code it uses a Java 2D Array "dp[][]" . So we can't initialize a 2D array for large rows and columns.
Ex : If i need to check 2 strings whose lengths are more than 100000
int[][] dp = new int[len1 + 1][len2 + 1];
the above will be
int[][] dp = new int[100000][100000];
So it will give a stackOverflow error.
So the above program only good for small length Strings.
What I'm asking is , Is there any way to solve this problem for large strings(length > 100000) efficiently in java.
First of all, there's no problem in allocating a 100k x 100k int array in Java, you just have to do it in the Heap, not the Stack (and on a machine with around 80GB of memory :))
Secondly, as a (very direct) hint:
Note that in your loop, you are only ever using 2 rows at a time - row i and row i+1. In fact, you calculate row i+1 from row i. Once you get i+1 you don't need to store row i anymore.
This neat trick allows you to store only 2 rows at the same time, bringing down the space complexity from n^2 to n. Since you stated that this is not homework (even though you're a CS undergrad by your profile...), I'll trust you to come up with the code yourself.
Come to think of it I recall having this exact problem when I was doing a class in my CS degree...
I'm trying to write a program which solves the maximum subarray problem. I can understand the intuition behind Kadane's Algorithm on a 1-D array as well as the O(N^4) implementation on a 2-D array. However, I am having some trouble understanding the O(N^3) implementation on a 2-D array.
1) Why do we add up the elements with those from the previous rows within the same column?
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= M; j++)
array[i][j] += array[i-1][j];
}
2) I have no understanding of the second part of the algorithm
Tried looking for an explanation on the web but to no avail. Hope to get some help here!
Thanks in advance!
You know how to compute maximum sum sub-array on a 1D array using Kadane's algorithm. Now we want to extend this algorithm for the 2D array. For an O(N^3) algorithm, we have an intuition. If we somehow create N^2 sub problems and then try to run our O(N) Kadane's algorithm, we can solve the maximum sub array problem.
So basically how we create the N^2 sub problems is by iterating over all the top and bottom rows of the matrix. Then we try to find the optimal columns between which the sub array exists by applying kadane's 1D algorithm. We thus sum the numbers between these two rows column wise and then apply kadane's 1D algorithm on this newly formed 1D array.
But we have a problem here. Computing the sums for all the O(n^2) ranges of the top and bottom rows will itself be O(n^4). This bottle neck can be overcome by modifying our matrix by replacing each element with the sum of all the numbers that are above it in that element's column. Thus, now we can find out the sum of numbers between any two rows in O(n) time by subtracting the appropriate arrays in the matrix.
The java pseudo code -
int kadane2D(int array[N][M]){
// Modify the array's elements to now hold the sum
// of all the numbers that are above that element in its column
for (int i = 1; i < N; i++) {
for (int j = 0; j < M; j++){
array[i][j] += array[i-1][j];
}
}
int ans = 0; // Holds the maximum sum matrix found till now
for(int bottom = 0; bottom < N; bottom++){
for(int top = bottom; top < N; top++){
// loop over all the N^2 sub problems
int[] sums = new int[N];
// store the sum of numbers between the two rows
// in the sums array
for(int i = 0; i < M; i++){
if (bottom > 0) {
sums[i] = array[top][i] - array[bottom-1][i];
} else {
sums[i] = array[top][i];
}
}
// O(n) time to run 1D kadane's on this sums array
ans = Math.max(ans, kadane1d(sums));
}
}
return ans;
}
For people who understand the Kadane's 1D algorithm, below should be easy to understand. Basically we try to convert the 2D matrix into 1D by using the prefix sum for each rows. And for each prefix sum row, we just apply the Kadane's 1D algorithm.
Just posting the working Python code:
class Kadane2D:
def maxSumRetangle(self, grid):
def kadane1D(arr):
curmax, maxsofar = 0, float('-inf')
for a in arr:
curmax = max(a, curmax + a)
maxsofar = max(curmax, maxsofar)
return maxsofar
m, n, ans = len(grid), len(grid[0]), float('-inf')
colCum = [[0] * n]
for row in grid:
colCum.append([pre + now for pre, now in zip(colCum[-1], row)])
for top in range(1, m + 1):
for bottom in range(top, m + 1):
sums = [b - t for b, t in zip(colCum[bottom], colCum[top - 1])]
ans = max(ans, kadane1D(sums))
return ans
grid = [[1, 2, - 3], [3, 4, -6]]
assert Kadane2D().maxSumRetangle(grid) == 10
grid = [[1, 2, -1, -4, -20],
[-8, -3, 4, 2, 1],
[3, 8, 10, 1, 3],
[-4, -1, 1, 7, -6]]
assert Kadane2D().maxSumRetangle(grid) == 29
I know it's an old question. But Google doesn't have the right answers, or they're overworked.
No, this is no correct way. Working example, on O(N^2):
/**
* Kadane 1d
* #return max sum
*/
public static int maxSum(int[] a) {
int result = a[0]; //get first value for correct comparison
int sum = a[0];
for (int i = 1; i < a.length; i++) {
sum = Math.max(sum + a[i], a[i]); //first step getting max sum, temporary value
result = Math.max(result, sum);
}
return result;
}
/**
* Kadane 2d
* #param array
* #return max sum
*/
public static int maxSum2D(int array[][]){
int result = Integer.MIN_VALUE; //result max sum
for (int i = 0; i < array.length; i++) {
int sum = maxSum(array[i]);
result = Math.max(result, sum);
}
return result;
}
Fully examples:
Easy: https://pastebin.com/Qu1x0TL8
Supplemented: https://pastebin.com/Tjv602Ad
With indexes: https://pastebin.com/QsgPBfY6
I am trying to implement the midpoint displacement algorithm in Java. It's also called the diamond square algorithm. My reference is http://www.lighthouse3d.com/opengl/terrain/index.php3?mpd. It seems to work correctly except on the right and bottom edges.
See Midpoint Displacement Results
Upon close inspection, the "rough" edges can be seen. Could anyone point out what is wrong?
This effect hasn't been observed in other online implementations of this algorithm.
Code
private void generateWorldMPD() {
/* The following is my first attempt at the MDP algorithm. */
// displacement boundary.
double displacementBound = Constants.DEFAULT_ROUGHNESS_CONSTANT;
double[][] A = Utilities.get2DDoubleArray(Constants.MPD_PRESET_HEIGHT, 2, 2);
int iterations =0;
while (iterations < mPDIterations) {
// create a new array large enough for the new points being added.
double [][] B = new double[A.length * 2 - 1][A[0].length * 2 - 1];
// move the points in A to B, skipping every other element as space for a new point
for (int i = 0; i < B.length; i +=2)
for (int j = 0; j < B[i].length; j+=2) {
B[i][j] = A[i / 2][j / 2];
}
//calculate the height of each new center point as the average of the four adjacent elements
//(diamond step) and add a random displacement to each
for (int i = 1; i < B.length; i+= 2)
for (int j = 1; j < B[i].length; j+=2) {
averageFromCornersAndDisplace(B, i, j, displacementBound);
}
//calculate the height of each new non-center point (square step) and add a random displacement to each
for (int i = 0; i < B.length; i ++)
for (int j = 0; j < B[i].length; j++)
if (i % 2 == 0) //on every even row, calculate for only odd columns
if (j % 2 == 0) continue;
else
averageFromAdjAndDisplace( B , i, j, displacementBound );
else //on every odd row, calculate for only even columns
if (j % 2 == 0)
averageFromAdjAndDisplace( B , i, j, displacementBound );
else
continue;
displacementBound *= Math.pow(2, -Constants.DEFAULT_ROUGHNESS_CONSTANT);
// assign B to A
A = B;
iterations++;
}
}
private void averageFromCornersAndDisplace(double[][] A, int i, int j, double displacementBoundary) {
double nw = A[ wrap(i - 1, 0, A.length - 1) ][ wrap(j - 1, 0, A[i].length - 1) ];
double ne = A[ wrap(i + 1, 0, A.length - 1) ][ wrap(j - 1, 0, A[i].length - 1) ];
double sw = A[ wrap(i - 1, 0, A.length - 1) ][ wrap(j + 1, 0, A[i].length - 1) ];
double se = A[ wrap(i + 1, 0, A.length - 1) ][ wrap(j + 1, 0, A[i].length - 1) ];
A[i][j] = (nw + ne + sw + se) / 4;
A[i][j] += randomDisplacement(displacementBoundary);
}
private void averageFromAdjAndDisplace(double[][] A, int i, int j, double displacementBoundary) {
double north = A[i][ wrap(j - 1, 0, A[i].length - 1)];
double south = A[i][ wrap(j + 1, 0, A[i].length - 1)];
double west = A[ wrap(i - 1, 0, A.length - 1) ][j];
double east = A[ wrap(i + 1, 0, A.length - 1) ][j];
A[i][j] = (north + south + east + west) / 4;
A[i][j] += randomDisplacement(displacementBoundary);
}
// This function returns a value that is wrapped around the interval if
// it exceeds the given bounds in the negative or positive direction.
private int wrap(int n, int lowerBound, int upperBound) {
int lengthOfInterval = upperBound - lowerBound;
if (n < lowerBound)
return (lowerBound - n) % lengthOfInterval;
else
return (n - upperBound) % lengthOfInterval;
}
Annotations
private void generateWorldMPD() {
/* The following is my first attempt at the MDP algorithm. */
// displacement boundary.
double displacementBound = Constants.DEFAULT_ROUGHNESS_CONSTANT;
double[][] A = Utilities.get2DDoubleArray(Constants.MPD_PRESET_HEIGHT, 2, 2);
int iterations =0;
This part defines a variable displacementBound, a 2D array of doubles initialized to default values, and another variable called iterations.
while (iterations < mPDIterations) {
// create a new array large enough for the new points being added.
double [][] B = new double[A.length * 2 - 1][A[0].length * 2 - 1];
// move the points in A to B, skipping every other element as space for a new point
for (int i = 0; i < B.length; i +=2)
for (int j = 0; j < B[i].length; j+=2) {
B[i][j] = A[i / 2][j / 2];
}
This part is where the loop is declared. It will run for mPDIterations loops. A makeshift array B is created to hold an updated version of A, making B larger than A to hold new data points. After that there are two for loops, one nested inside another, which places the current values of A into the temporary B, taking care to leave every other row and every other column blank. Take a look at this example:
// The '*'s represent a cell in an array that is populated with a value.
// The '_'s represent a cell in an array that is empty.
// This is 'A'.
* *
* *
// This is 'B'. At the moment, completely empty.
_ _ _
_ _ _
_ _ _
// The elements of 'A' are tranferred to 'B'.
// Blank cells are inserted in every other row, and every other column.
* _ *
_ _ _
* _ *
Now for the next bit of code:
//calculate the height of each new center point as the average of the four adjacent elements
//(diamond step) and add a random displacement to each
for (int i = 1; i < B.length; i+= 2)
for (int j = 1; j < B[i].length; j+=2) {
averageFromCornersAndDisplace(B, i, j, displacementBound);
}
In this section, every point at a center, which refers to a cell that has an empty adjacent cell in every cardinal direction of north, south, east, and west, is given a value averaged from the four adjacent corner points and with a random displacement value added to it. This is called the diamond step. To clarify what a 'center' is:
// The big "O" indicates the 'center' in this 2D array.
* _ *
_ O _
* _ *
And the next code section:
//calculate the height of each new non-center point (square step) and add a random displacement to each
for (int i = 0; i < B.length; i ++)
for (int j = 0; j < B[i].length; j++)
if (i % 2 == 0) //on every even row, calculate for only odd columns
if (j % 2 == 0) continue;
else
averageFromAdjAndDisplace( B , i, j, displacementBound );
else //on every odd row, calculate for only even columns
if (j % 2 == 0)
averageFromAdjAndDisplace( B , i, j, displacementBound );
else
continue;
This part does is analogous to the previous section of code. It assigns to each non-center and empty point a new value; this value is the average of the adjacent elements in the cardinal directions north, south, east, and west, with another random displacement value added to it. This is called the square step. The code above assures that only the non-center and empty points are given new values; these points being equivalent to side points, which are clarified below:
// The big 'O's indicate the 'side points' in this 2D array.
* O *
O * O
* O *
The section that concludes the while loop is given below:
displacementBound *= Math.pow(2, -Constants.DEFAULT_ROUGHNESS_CONSTANT);
// assign B to A
A = B;
iterations++;
} // end of while loop
The variable displacementBound is reduced in the section above, which comprises the end of the while loop, according to the information given in the aforementioned article. The contents of A are renewed by assigning the updated contents of B to A prior to beginning another iteration of the loop or terminating it.
Lastly, the ancillary methods averageFromCornersAndDisplace(), averageFromSidesAndDisplace(), and wrap() have been included but additional explanations for them are unnecessary. The method randomDisplacement() has not been included at all. For your information, it returns a random floating-point number x bounded by the given number b:
// The method returns a double x, where -b <= x < b
double randomDisplacement(double b);
I just saw your post pop up, and I guess you've already sorted it out. Anyway, if you want to do a wrap like that, there is a neat trick to fix the fact that negative mods don't work right in C/Java. What you do is just add some multiple of the modulus (being careful not to overflow) back to the number to ensure that it is non-negative. Then you can mod out as usual without it breaking. Here is an example:
private int wrap(int n, int lowerBound, int upperBound) {
int lengthOfInterval = upperBound - lowerBound;
return lowerBound + ((n - lowerBound + lengthOfInterval) % lengthOfInterval);
}
The wrap() function is the culprit. It wraps indexes around when they exceed the boundaries of the array, so that on the edges two (often disparate) values are averaged together. Which lead to the weird incompatibility. I deleted all calls to wrap() and chose to average three adjacent points instead of four whenever wrapping was necessary.
The method wrap() was meant to provide seamless tiling, but in this case seems to have caused a problem. And the tiling doesn't even look seamless.