1

I came across below problem related to Matrix Manipulation.

problem statement

There is a NxN matrix,divided into N * N cells. Each cell has a predefined value. Which would be given as an input. Iteration has to happen K number of times which is also given in the test input. We have to make sure that we pick the optimum/min value of rows/columns at each iteration. Final output is the cumulative sum of optimum value saved at the end of each iteration.

Steps 1. Sum up the individual row and column and find the min sum of rows and columns, (it could be a row or a column, just need the minimum row or a column)

Step 2. Store the sum found above separately

Step 3. Increment elements of the min. sum row or column. by 1

Repeat steps 1,2,3 from 1 to Kth value

add the sum at each iteration(specified in step2)

output is the sum obtained on on the Kth iteration.

Sample data

2 4
1 3
2 4

Output data

22

I was able to write a code (in java) and tested the same for some sample test cases. The output worked fine. The code works fine for sample data matrix of lower order, say, 2x2,4x4,even till 44x40 (that has less iteration). However, when the matrix size is increased to 100X100 (complex iteration), I see the expected output output values differ at 10s and hundreds place of the digit from the actual output and its random. Since I am not able to find a correct pattern of output vs input. Now, it is taking a toll on me to really debugging 500th loop to identify the issue. Is there any better way or approach to solve such problem related to huge matrix manipulation. Has anyone come across issues similar to this and solved it.

I am mainly interested in knowing the correct approach to solve given matrix problem. What Data structure to use in java. At present, I am using primitive DS and arrays int[] or long[] to solve this problem. Appreciate any help in this regard.

yeppe
  • 679
  • 1
  • 11
  • 43
  • Have you tried using long[][], It maybe because of integer overflow. – FazeL Jul 18 '16 at 05:01
  • Try my answer's algorithm too, that is far easier to implement (thus less bug prone) and more efficient than the naive approach. – FazeL Jul 18 '16 at 08:52
  • I think you keep the matrix. The pic used the matrix to show you don't need to keep all the matrix but just values in the side of it, an 2 by N array not an N by N one. Is it the case? – FazeL Jul 20 '16 at 05:16

3 Answers3

2

Which data structure?

What you need here is a data structure which allows you to efficiently query and update the minimum sum line. The most commonly used for this is a heap https://en.wikipedia.org/wiki/Heap_(data_structure).

For your purposes it's probably best to just implement the simplest kind, an array-based binary heap:

..for implementation details.


Procedure:

  • Initialize your heap to size M + N where M, N are the number of rows and columns.
  • Before the loop, pre-compute the sum of each row and column, and add them as objects to the heap. Also add two arrays A, B which store the row and columon objects separately.
  • Now heapify the heap array with respect to the line sum attribute. This ensures the heap follows the criterion of the binary heap structure (parent always > children). Read the sources to find out more about how to implement this (quite easy for a fixed array)
  • For each iteration, look at the first element in the heap array. This is always the one with the smallest line sum. If this is a row object, then increment the sum attribute by N (no. of columns), and increment each object in B (list of columns) by 1. Do the same if it's a column.
  • After this, always heapify before the next iteration.

At the end, just return the first element's attribute.


Time complexity:

The original naive solution (looping through all columns and rows every time) is enter image description here.

Using a heap, the heapify operation at each step is enter image description here (for a binary heap).

This means the total complexity is ![enter image description here, FAR smaller. The max term is to compensate for the fact that at each iteration it may be either rows or columns which are incremented.


As a side note, there are other heap structure types which have even better time complexity than the binary heap, e.g. binomial trees, Fibonacci heaps etc. These however are far more complicated, and have higher constant-factor overheads as a result. Thus for your project I feel they are not necessary, as many of them need phenomenal data set sizes to justify for the constant factor overhead.

Besides, they all support the same external operations as the binary heap, as defined by the Abstract Data Structure of Heap.

(heapify is an internal operation specific to the binary heap structure. Quite a few of the other ones are theoretically superior as they do this operation implicitly and "lazily")

  • here are two implementations: http://eddmann.com/posts/implementing-heapsort-in-java-and-c/. both are recursive and thus slightly more intuitive to follow (though _marginally_ less efficient than an iterative one). I have no idea why your code differs for higher o/p unfortunately; the only way I can know is if you show your code so far. Apologies that the original java implementation I referred to lacked the heapify operation (AKA build-heap) - the author preferred the one-at-a-time approach, which would be less efficient in our case. –  Jul 19 '16 at 19:07
1

O(KN + N*N) Solution:
You can just work with sum of columns and rows, and not store or manipulate them directly.



First sum all the columns and rows, in a 2*N array, first row being sum of columns, a[0][0] is sum of first column, a[0][1] is sum of second column, and second row is sum of rows, a[1][0] sum of first row, etc...
Then do the following for iterating:
  1. Find min in array a .
  2. Add it to the answer.
  3. Add N to the min of row or column selected.
  4. If the min is row add one to all cols and if it is a column add one to all rows. solved example If needed any further explanation, don't hesitate to comment.
FazeL
  • 916
  • 2
  • 13
  • 30
  • 1
    @yeppe do you keep a list of sums of rows and columns, in each iteration or just keep the the whole matrix, and do the operation on and actually add one to all elements of the row or col and then sum up the values again in each iteration? – FazeL Jul 20 '16 at 05:20
1

I am doing like this for solving the above problem...

        void matrixManipulation() throws IOException {
            int N = Reader.nextInt();
            int[][] matrix = new int[N][N];
            int K = Reader.nextInt();
            for (int i = 0; i < N; i++) {
                for (int j = 0; j < N; j++) {
                    matrix[i][j] = Reader.nextInt();
                }
            }

    //      System.out.println("********Inital position**********");
    //      for (int i = 0; i < N; i++) {
    //          for (int j = 0; j < N; j++) {
    //              System.out.print(matrix[i][j]);
    //          }
    //          System.out.println();
    //      }
    //      System.out.println("********Inital position**********");

            CalculateSum calculateSum = new CalculateSum();

            int[] row = new int[N];
            int[] row_clone = new int[N];

            int[] col = new int[N];
            int[] col_clone = new int[N];

            int test =0;

            for (int kk = 0; kk < K; kk++) {

                row = calculateSum.calculateRowSum(matrix, N);
                row_clone = row.clone();
/* just sort it either Arrarys sort or any other ---starts here*/
    //          for (int i = 1; i < row.length; i++) {
    //              row_orignial[i] = row[i];
    //          }
    //          Arrays.sort(row);
                Node root1 = insert(null, row[0], 0, row.length);
                for (int i = 1; i < row.length; i++) {
                    insert(root1, row[i], 0, row.length);
                }
                sortArrayInOrderTrvsl(root1, row, 0);

    /* just sort it either Arrarys sort or any other ---ends here*/


                col = calculateSum.calculateColumnSum(matrix, N);
                col_clone = col.clone();

/* just sort it either Arrarys sort or any other ---starts here*/
    //          for (int i = 1; i < col.length; i++) {
    //              col_orignial[i] = col[i];
    //          }
    //          Arrays.sort(col);
                Node root2 = insert(null, col[0], 0, col.length);
                for (int i = 1; i < row.length; i++) {
                    insert(root2, col[i], 0, col.length);
                }
                sortArrayInOrderTrvsl(root2, col, 0);

/* just sort it either Arrary.sort or any other---ends here */

                int pick = 0;
                boolean rowflag = false;
                int rowNumber = 0;
                int colNumber = 0;
                if (row[0] < col[0]) {
                    pick = row[0];// value
                    rowflag = true;
                    for (int i = 0; i < N; i++) {
                        if (pick == row_clone[i])
                            rowNumber = i;
                    }
                } else if (row[0] > col[0]) {
                    pick = col[0];// value
                    rowflag = false;
                    for (int i = 0; i < N; i++) {
                        if (pick == col_clone[i])
                            colNumber = i;
                    }
                } else if(row[0] == col[0]){
                    pick = col[0];
                    rowflag = false;
                    for (int i = 0; i < N; i++) {
                        if (pick == col_clone[i])
                            colNumber = i;
                    }
                }
                test= test + pick;

                if (rowflag) {
                    matrix = rowUpdate(matrix, N, rowNumber);
                } else {
                    matrix = columnUpdate(matrix, N, colNumber);

                }
                System.out.println(test);

    //          System.out.println("********Update Count"+kk+" position**********");
    //          for (int i = 0; i < N; i++) {
    //              for (int j = 0; j < N; j++) {
    //                  System.out.print(matrix[i][j]);
    //              }System.out.println();
    //          }
    //          System.out.println("********Update Count"+kk+" position**********");

            }

    //      System.out.println("********Final position**********");
    //      for (int i = 0; i < N; i++) {
    //          for (int j = 0; j < N; j++) {
    //              System.out.print(matrix[i][j]);
    //          }System.out.println();
    //      }
    //      System.out.println("********Final position**********");
    //      System.out.println(test);
        }
yeppe
  • 679
  • 1
  • 11
  • 43
  • 1
    You seem to be sorting a binary tree..? This takes O(n log n) average case (O(n^2) worst), where as a simple heapify takes just O(n). –  Jul 21 '16 at 12:16
  • 1
    I will implement my solution that works for matrices of higher order and send it the day after tomorrow, I am busy at an startup event – FazeL Jul 21 '16 at 19:47