Is there a function which keeps increasing a number in a matrix in given order

Viewed 138

I have to create a matrix (N*M) where each cell is labeled in according to their order with specific traversal.

The problem is that I have it only working for (NN). I am stuck to find a solution so it can also work for (NM).

For instance Example with N*M:

1  2  5  10

4  3  6  11

9  8  7  12

Example with N*N:

1  2  5  10 

4  3  6  11 

9  8  7  12 

16 15 14 13

2x4 will look like:

1 2 5 7

4 3 6 8

4x2 will look like:

1 2

4 3

5 6

7 8

Code

public static int matrix[][];
       public static void main(String[] args) {

        borderLayout(5);
        print();
       }

       public static void borderLayout(int size) {
           matrix = new int[size][size];
           for(int i = 0 ; i < size ; i ++) {
               fillBorder(i);
           }
       }

       public static void fillBorder(int n) {
           int number = n*n+1;
           int row = n;
           int column = 0;


           for(column = 0; column<=n; column++) {
               System.out.println("COLUMN DRAWING");
               matrix[row][column]=number++;
           }

           column--;

           for(row = n; row>0 ; row--){
               System.out.println("ROW DRAWING");
               matrix[row-1][column] = number++;
           }

           print();
           System.out.println("");

       }

       private static void print() {

              int x = matrix.length;
              int y = matrix[0].length;

              for (int i = 0; i < x; i++) {

                 for (int j = 0; j < y; j++) {

                    System.out.print(matrix[j][i]);
                    System.out.print(" ");
                    if (matrix[j][i] < 10) {
                       System.out.print(" ");
                    }
                 }

                 System.out.println();
              }

           }
3 Answers

Following your comments under my first answer:

I was thinking also for another solution...With BFS. For a starting point let's say 0,0 you always go depth 1 every iteration so if you start from 0,0 you then do 1,0 1,1 0,1 and when you hit boundaries either row or column you increment the depth that means on the next iteration you go with 0,2 1,2 2,2 2,1 2,0 and if the matrix is nxm with n!=m you just skip the col or the row based on where you are(check matrix bound always m and n).

Forgot ot mention that in this way it will also work for letters as well.

I dicided to add a new answer instead of editing the first one.

As I am not very familliar with graphs and breadth first search I can't give any advice for BSF based algorithms.

But I think I understood your idea of how you would like to proceed and here is a naive approach to implement it. The steps you want to take at each iteration

0,0
-----
0,1
1,1
1,0
-----
0,2
1,2
2,2
2,1
2,0
-----
0,3
1,3
2,3
3,3
3,2
3,1
3,0
...

Regardless of whether the matrix is square or not, I initially concentrate on the square-area. For example, if it is a 4x6 matrix, I only look at the 4x4 part and ignore the last two columns. Similarly if the rows are larger than the columns. For a 7x5 I will look at 5x5 and ignore the last two lines. At each iteration I will use two inner loops, the first one to increment rows and the second to decrement columns.

In contrast to the previous answer, this time I will use a string array to fulfill this comment from you:

Forgot ot mention that in this way it will also work for letters as well.

static String[][] fillArray(int rows, int columns){
    char ch = 'A';
    String[][] matrix = new String[rows][columns];
    int square = Math.min(rows, columns);
    for(int i = 0; i < square; i++){
        String curr = String.valueOf(ch);
        for(int r = 0; r <= i ; r++){
            matrix[r][i] = curr;
        }
        for(int c = i-1; c >= 0; c--){
            matrix[i][c] = curr;
        }
        ch++;
    }
    return matrix;
}

Calling the above method for example with the args 4x5

public static void main(String[] args) {
    String[][] filled = fillArray(4,5);
    for(String[] row: filled){
        System.out.println(Arrays.toString(row));
    }
}

will result in

[A, B, C, D, null]
[B, B, C, D, null]
[C, C, C, D, null]
[D, D, D, D, null]

Now let's look at the ignored area which is still filled with null, i.e the cases where rows > columns or rows < columns. For the sake of simplicity I will fill out this area with *.

static String[][] fillArray(int rows, int columns){
    char ch = 'A';
    String[][] matrix = new String[rows][columns];
    int square = Math.min(rows, columns);
    for(int i = 0; i < square; i++){
        String curr = String.valueOf(ch);
        for(int r = 0; r <= i ; r++){
            matrix[r][i] = curr;
        }
        for(int c = i-1; c >= 0; c--){
            matrix[i][c] = curr;
        }
        ch++;
    }

    ch = '*';
    if (rows > columns) {
        for (int i = square; i < rows; i++) {
            for (int j = 0; j < columns; j++) {
                matrix[i][j] = String.valueOf(ch);
            }
        }
    }
    if (rows < columns) {
        for (int i = square; i < columns; i++) {
            for (int j = 0; j < rows; j++) {
                matrix[j][i] = String.valueOf(ch);
            }
        }
    }
    return matrix;
}

Calling fillArray(4,6)

public static void main(String[] args) {
    String[][] filled = fillArray(4,6);
    for(String[] row: filled){
        System.out.println(Arrays.toString(row));
    }
}

should now result in:

[A, B, C, D, *, *]
[B, B, C, D, *, *]
[C, C, C, D, *, *]
[D, D, D, D, *, *]

This post has become longer than I actually thought. But I hope it's pretty easy to understand.

If you look at your nxn matrix there is a certain pattern to recognise.

   1    2    5   10   17 
   4    3    6   11   18 
   9    8    7   12   19 
  16   15   14   13   20 
  25   24   23   22   21 
  • In the first column there are always square numbers
  • In the first row starting from the smallest square number 1 you are adding the sequence of odd numbers, i.e. 1,3,5,7,9,11 ....

The patern for each row

[1]  +1 +3 +5 +7 ....
[4]  -1 +3 +5 +7 ....
[9]  -1 -1 +5 +7 ....
[16] -1 -1 -1 +7 ....
[25] -1 -1 -1 -1 ....

With this knowledge it is now easy to fill an n x n matrix. Create a list with the odd numbers from 1 to columns-1, fill the first row by adding the elements of your list one after the other, after each iteration replace the ith number in the list with -1 to be able to use the list for the i+1th row.

Now for a non-square matrix, you can use the above approach to fill the square area of the matrix and handle the remaining rows or columns separately. Finding the size of the square area in order to difine a counter for the rest of rows/columns is relative simple.

Just calculate Math.pow(Math.min(rows, columns), 2);

I've adopted your method names and changed your print method a bit. I did not comment the code, but hope it is clear what is being done. If anything is unclear do not hesitate to ask.

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Test{

    public static int matrix[][];

    public static void main(String[] args) {
        borderLayout(5, 5);
        print();
    }

    public static void borderLayout(int rows, int columns) {
        //create a list (1,3,5, ...) with size = columns - 1
        List<Integer> list = IntStream.iterate(1, i -> i + 2)
                .limit(columns - 1).boxed()
                .collect(Collectors.toList());
        matrix = new int[rows][columns];
        int square = Math.min(rows, columns);
        for (int i = 0; i < square; i++) {
            int temp = (i + 1) * (i + 1);
            for (int j = 0; j < square; j++) {
                if (j == 0) {
                    matrix[i][j] = temp;
                } else {
                    matrix[i][j] = matrix[i][j - 1] + list.get(j - 1);
                }
            }
            if (i < columns - 1) {
                list.set(i, -1);
            }
        }
        if (rows > columns) {
            int counter = (int) Math.pow(Math.min(rows, columns), 2);
            int sqrt = (int) Math.sqrt(counter);
            for (int i = sqrt; i < rows; i++) {
                for (int j = 0; j < columns; j++) {
                    matrix[i][j] = ++counter;
                }
            }
        } else if (rows < columns) {
            int counter = (int) Math.pow(Math.min(rows, columns), 2);
            int sqrt = (int) Math.sqrt(counter);
            for (int i = sqrt; i < columns; i++) {
                for (int j = 0; j < rows; j++) {
                    matrix[j][i] = ++counter;
                }
            }
        }
    }

    private static void print() {
        for (int[] row : matrix) {
            for (int i : row) {
                System.out.printf("%4d ", i);
            }
            System.out.println();
        }
    }
}

If you look along the left column, there is a pattern:

 1
 4
 9
16

which is (r + 1)^2, where r is the row number.

Along the rows, the value decreases by 1, up to the diagonal where r == c:

 1
 4  3 
 9  8  7
16 15 14 13

which is (r + 1)^2 - c.

If you look along the top row, there is a pattern:

1   2   5   10

which is c^2 + 1.

Down the columns rows, the value increases by 1, up to the diagonal where r == c:

1   2   5   10
    3   6   11
        7   12
            13

which is c^2 + 1 + r

So you can calculate the array elements using nested loops:

for (int r = 0; r < N; ++r) {
  for (int c = 0; c < M; ++c) {
    matrix[r][c] = (r >= c) ? ((r + 1)*(r + 1) - c) : (c * c + 1 + r);
  }
}
Related