How to fill a 2D array with a constant value with better efficiency than n ^ 2?

This is a general question that can be applied to any language such as C, C ++, Java, etc.
I understand how you implement it, you cannot get more efficient than using 2 cycles, which gives an efficiency of n ^ 2.

for(i=0;i<n;i++) for(j=0;j<n;j++) a[i][j]=1; 

I was recently asked about this in an interview, and I could not think of anything more effective. All I got from the interviewer was that I could use recursion or convert a 2D array to a linked list to make it more efficient than n ^ 2. Does anyone know if this is possible, and if so , how? At least theoretically, if not practically.

edit: The actual question gives me the coordinates of two cells, and I have to fill in the paths made by all possible shortest routes using 1. for example, if I have a 5x5 matrix, and my two coordinates are (2.0) and (3.3) I need to fill in:
(2.0) (2.1) (2.2) (2.3) (3.0) (3.1) (3.2) (3.3)
leaving the rest of the cells as they were.

+4
source share
3 answers

It depends on what you mean. If we are talking about simple arrays, which means a sequence of contiguos memory locations, and for initialization, you mean the value for each memory cell of this “matrix”, then the answer is no , better than O (n * m) is impossible, and we can do it prove:

Suppose that the correct fill(A[n][m], init_val) (that is, fills all the memory cells of A ) has a complexity g(n,m) that is less than O(n*m) (the value g(n,m) not part of Ω(n*m) ), then for sufficiently large n and m we will have g(n,m) < n*m = the number of memory locations. Since filling a memory cell requires one operation, the fill algorithm can fill in no more than g(n,m) locations [actually half, because it should also perform at least the operation “select” another memory location, unless the hardware provides combined operation], which is strictly less than n*m , which means that the fill algorithm is incorrect.

The same thing happens if filling memory cell k takes a constant time, you just need to select larger values ​​of n and m .

As already mentioned, you can use other data structures to avoid the initialization time O(n^2) . amit suggestion uses some kind of lazy evaluation, which allows us not to initialize the array at all, but to do it only when accessing elements.

Note that this removes the cost of Ω(n^2) at the beginning, but requires more complex operations to access the elements of the array, and also requires more memory.

It is not clear what your interviewer had in mind: it takes time Ω(L) to convert an array to a linked list (where L is the length of the array), so just converting the entire matrix to a linked list will take Ω(n^2) time plus real initialization. Using recursion does not help at all, you just find yourself in recurrence expressions such as T(n) = 2T(n/2) + O(1) , which again will not be useful for asymptotic complexity.

As a rule, all algorithms should scan at least all of their data, except that they have some form of knowledge in advance (for example, items are sorted). In your case, the scanning space is Θ(n^2) , and therefore each algorithm that wants to fill it must be at least Ω(n^2) . Anything less than this complexity either makes some assumptions (for example, memory contains the default initializer value → O(1) ), or solves another problem (for example, use lazy arrays or other data structures).

+6
source

You can initialize the array in O(1) , but it consumes three times the amount of space and additional “work” for each access element in the matrix.
Since in practice the matrix is ​​a 1D array in memory, the same principles are still preserved.

The page describes how to do this in detail.

+4
source

When you fill a 2d array with the same element, if you really will fill each element , at least n ^ 2 must be executed. (given that the 2nd array is n * n).

The only way to reduce complexity is to use a parallel programming approach. For example, for a given n processor, the first input is assigned to the first line of the array. These are n operations. Then each processor Pi assigns an array [i] of row k to an array [i] of row k + 1 for k = 0 to n-1. This will be O (n) again, since the n processor runs in parallel.

If you really want to implement this approach, you can search for free parallel programming environments such as OpenMPI and mpich

0
source

All Articles