Toeplitz matrix in Java

A Toeplitz matrix is a special type of matrix in linear algebra where each descending diagonal from left to right contains the same elements. It is named after the mathematician Otto Toeplitz. A Toeplitz matrix is a square matrix of size n×n in which each cell A[i][j] contains the same value as A[i-1][j-1], A[i+1][j+1], A[i-2][j-2], A[i+2][j+2], and so on, for all valid cells A[i+k][j+k] or A[i-k][j-k]. In simpler terms, the elements along each diagonal are constant.

Examples:

Input:

Toeplitz matrix in Java

Output:

 
True   

Input:

Toeplitz matrix in Java

Output:

 
True   

Input:

Toeplitz matrix in Java

Output:

 
False   

Approach: Diagonal Comparison

The approach is simple we examine each element in the matrix's first row and first column (or the last row and last column). We trace the descending diagonal for each of these elements and verify if all its elements have identical values. We immediately return false if we encounter any descending diagonal with varying values.

As for the implementation, we'll need to use nested loops to Iterate through the matrix and check the descending diagonals. If all the diagonals have the same values, the method should return true; otherwise, it returns false.

The implementation of the above code:

Algorithm:

Step 1: Create a method checkDiagonal(matrix, row, col) to check if all elements in the descending diagonal, starting from position (row, col) in the matrix, are the same.

Step 2: Create a method isToeplitz(matrix) to check if all descending diagonals from left to right in the matrix have the same elements.

Step 3: Iterate through each element in the first row and check it's descending diagonal using checkDiagonal(matrix, 0, i).

Step 4: Iterate through each element in the first column and check it's descending diagonal using checkDiagonal(matrix, i, 0).

Step 5: If any descending diagonal has different elements, return false; otherwise, return true after both loops.

Implementation:

Filename: ToeplitzMatrixChecker1.java

Output:

 
The given matrix is a Toeplitz matrix.   

Time Complexity: Time Complexity:

The time complexity of the code is O(N * M), where N is the number of rows in the matrix, and M is the number of columns in the matrix. The time complexity is because the code iterates through all matrix elements starting from the first row and first column. It checks each element's descending diagonal until it reaches the bottom-right corner.

Auxiliary Space: The auxiliary space complexity of the code is O(1).

Improvement in The Above Approach

The algorithm involves a full matrix traversal, where each element is compared to its diagonally above element. If any element does not match its diagonal neighbor, the matrix is not considered "Toeplitz," and the method returns false. However, if all elements satisfy the condition, the method returns true, indicating that the matrix is a "Toeplitz" matrix.

Filename: ToeplitzMatrixChecker2.java

Output:

 
The given matrix is a Toeplitz matrix.   

Time Complexity: The time complexity of the provided code is O(N * M), where N is the number of rows in the matrix, and M is the number of columns in the matrix. The time complexity is because the code iterates through all matrix elements from (1, 1) to (N-1, M-1), performing a constant-time comparison for each element.

Auxiliary Space: The auxiliary space complexity of the code is O(1), which means that the amount of extra space used by the code remains constant, regardless of the size of the input matrix.

Approach: Hashing based approach

In a matrix of dimensions (m, n), let's consider an element at index (i, j). For the matrix to be diagonal-constant, it requires all elements in the diagonal containing the element (i, j) to be the same. We can identify the other elements in this diagonal based on their indices, which follow the pattern (i+k, j+k) or (i-k, j-k). Remarkably, regardless of these indices' specific (x, y) values, their difference remains constant, equal to (i - j).

To illustrate this concept further, we can visualize it with a diagram. Take the diagonal colored yellow as an example. The difference between the x-values and y-values of any index on this diagonal is consistently 2 (e.g., 2-0, 3-1, 4-2, 5-3). The same observation can be extended to all other body diagonals within the matrix.

Toeplitz matrix in Java

Each diagonal has a unique difference value in the context of a Toeplitz matrix. For example, the red-colored diagonal has a difference of 3 between its x-values and y-values, the green-colored diagonal has a difference of 0, and the orange-colored diagonal has a difference of -2, and so on.

By leveraging this property, we can exploit that a constant-diagonal matrix should have unique elements on each diagonal. To achieve this, we use a HashMap to store key-value pairs. The keys represent the unique index differences for particular diagonals, and the corresponding values will be any element found on that diagonal.

During the process, if we encounter an element whose value does not match its corresponding stored key value in the HashMap, we can immediately conclude that the matrix is not constant-diagonal and can return false. Otherwise, if all elements on their respective diagonals maintain this property, the matrix is indeed constant-diagonal, and we can return true.

Algorithm:

Step 1: Create a hash map to store the elements of the matrix.

Step 2: Iterate through each element in the matrix.

Step 3: Check if the current diagonal key is already present in the map.

Step 4: If the current diagonal key is present in the map, compare the current element with the corresponding element.

Step 5: If the elements do not match, the matrix is not a Toeplitz matrix.

Step 6: If the diagonal key is absent in the map, add it along with the current element.

Step 7: If all elements satisfy the Toeplitz property, the matrix is a Toeplitz matrix.

Implementation:

Filename: ToeplitzMatrixChecker.java

Output:

 
The given matrix is a Toeplitz matrix.   

Time Complexity: The time complexity of the provided code is O(numRows * numCols), where numRows and numCols are the number of rows and columns in the input matrix, respectively. It is because the code iterates through all matrix elements exactly once, and for each element, it performs a constant-time lookup or insertion in the HashMap.

Auxiliary Space: The auxiliary space complexity of the code is also O(numRows * numCols). It is due to the space used to store the HashMap (diagonalMap), which can have a maximum of numRows * numCols key-value pairs in the worst case.