1886. Determine Whether Matrix Can Be Obtained By Rotation
Problem Description
You are given two square binary matrices of the same size: mat
and target
. Each matrix is n x n
in size and contains only 0s and 1s.
Your task is to determine if you can transform mat
to exactly match target
by rotating mat
in 90-degree increments. You can rotate the matrix 0, 1, 2, or 3 times (where 0 rotations means no change, and each rotation is 90 degrees clockwise).
The function should return true
if mat
can be made equal to target
through rotation, and false
otherwise.
For example, if you have a 2x2 matrix:
[[0,1], [1,0]]
After a 90-degree clockwise rotation, it becomes:
[[1,0], [0,1]]
The solution works by:
- Checking if
mat
already equalstarget
(0 rotations) - Rotating
mat
by 90 degrees and checking again - Repeating this process up to 4 times total (since 4 rotations of 90 degrees returns to the original position)
The rotation algorithm used in the code performs an in-place rotation by swapping elements in cycles around the matrix. For each layer of the matrix (working from outside to inside), it rotates four elements at a time in a circular pattern.
Intuition
The key insight is that rotating a matrix by 90 degrees clockwise exactly 4 times brings it back to its original position. This creates a cycle: original → 90° → 180° → 270° → 360° (back to original).
Since we want to check if mat
can become target
through rotation, we only need to check at most 4 positions:
- The original position (0 rotations)
- After 90° rotation (1 rotation)
- After 180° rotation (2 rotations)
- After 270° rotation (3 rotations)
If target
matches mat
at any of these 4 positions, then we can transform mat
into target
.
The approach becomes straightforward: keep rotating mat
and checking if it equals target
after each rotation. If we find a match within 4 rotations, return true
. If we've checked all 4 possible orientations without finding a match, return false
.
For the rotation itself, we can perform it in-place to save space. The rotation works by moving elements in groups of 4 around the matrix. For a 90-degree clockwise rotation:
- Top row elements move to the right column
- Right column elements move to the bottom row (reversed)
- Bottom row elements move to the left column
- Left column elements move to the top row (reversed)
This cycle of 4 swaps is performed for each "layer" of the matrix, working from the outermost layer inward. The formula matrix[i][j] → matrix[j][n-1-i]
captures this transformation mathematically.
Solution Approach
The solution implements a straightforward approach with two main components: a rotation function and a checking loop.
Main Logic:
The solution tries all 4 possible rotations of mat
and checks if any of them match target
:
for _ in range(4):
if mat == target:
return True
rotate(mat)
return False
This loop runs exactly 4 times because after 4 rotations of 90 degrees, we're back to the original matrix. If no match is found after checking all 4 orientations, we return false
.
In-Place Rotation Algorithm:
The rotate
function performs a 90-degree clockwise rotation in-place using a layer-by-layer approach:
def rotate(matrix):
n = len(matrix)
for i in range(n // 2):
for j in range(i, n - 1 - i):
# Perform 4-way swap
The rotation works by processing the matrix in concentric square layers from outside to inside:
i
represents the current layer (0 for outermost, 1 for next inner layer, etc.)- We only need to process
n // 2
layers - For each layer, we iterate through elements from position
i
ton - 1 - i
Four-Way Element Swap: For each element in a layer, we perform a cyclic swap of 4 elements:
t = matrix[i][j] # Save top element matrix[i][j] = matrix[n - j - 1][i] # Left → Top matrix[n - j - 1][i] = matrix[n - i - 1][n - j - 1] # Bottom → Left matrix[n - i - 1][n - j - 1] = matrix[j][n - i - 1] # Right → Bottom matrix[j][n - i - 1] = t # Top → Right
The indices follow the pattern for 90-degree clockwise rotation:
(i, j)
→(j, n-1-i)
→(n-1-i, n-1-j)
→(n-1-j, i)
→ back to(i, j)
Time and Space Complexity:
- Time:
O(n²)
for each rotation × 4 rotations =O(n²)
- Space:
O(1)
as the rotation is done in-place
The elegance of this solution lies in its simplicity - rather than computing all rotations separately or using complex mathematical transformations, it simply rotates and checks, leveraging the fact that there are only 4 possible orientations to consider.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a concrete example to illustrate how the solution works.
Given:
mat = [[0,1],[1,0]]
target = [[1,0],[0,1]]
Step 1: Check original matrix (0 rotations)
mat: [[0,1], target: [[1,0], [1,0]] [0,1]]
Compare: mat ≠ target
, so continue.
Step 2: Rotate mat by 90° clockwise
The rotation process for this 2×2 matrix:
- We have 1 layer (since n//2 = 2//2 = 1)
- For layer 0, we process element at position (0,0)
- Perform 4-way swap:
- Save top: temp = mat[0][0] = 0
- Left → Top: mat[0][0] = mat[1][0] = 1
- Bottom → Left: mat[1][0] = mat[1][1] = 0
- Right → Bottom: mat[1][1] = mat[0][1] = 1
- Top → Right: mat[0][1] = temp = 0
After rotation:
mat: [[1,0], target: [[1,0], [0,1]] [0,1]]
Compare: mat == target
✓ Return true
!
Let's trace another example where we need more rotations:
Given:
mat = [[1,1],[0,1]]
target = [[1,0],[1,1]]
Iteration 1 (0 rotations):
mat: [[1,1], target: [[1,0], [0,1]] [1,1]]
Not equal, rotate.
Iteration 2 (90° rotation): After rotating mat:
mat: [[0,1], target: [[1,0], [1,1]] [1,1]]
Not equal, rotate again.
Iteration 3 (180° total rotation): After rotating mat:
mat: [[1,0], target: [[1,0], [1,1]] [1,1]]
Compare: mat == target
✓ Return true
!
The algorithm found that after 2 rotations (180°), mat
matches target
.
For a case that returns false
, consider:
mat = [[1,1],[1,1]]
target = [[0,0],[0,0]]
No matter how many times we rotate a matrix of all 1s, it will never match a matrix of all 0s. After checking all 4 orientations, the algorithm returns false
.
Solution Implementation
1class Solution:
2 def findRotation(self, mat: List[List[int]], target: List[List[int]]) -> bool:
3 """
4 Determines if matrix 'mat' can be rotated (0, 90, 180, or 270 degrees) to match 'target'.
5
6 Args:
7 mat: Source matrix to rotate
8 target: Target matrix to match
9
10 Returns:
11 True if mat can be rotated to match target, False otherwise
12 """
13
14 def rotate_90_clockwise(matrix: List[List[int]]) -> None:
15 """
16 Rotates the matrix 90 degrees clockwise in-place using a layer-by-layer approach.
17
18 Args:
19 matrix: Square matrix to rotate in-place
20 """
21 n = len(matrix)
22
23 # Process the matrix layer by layer from outside to inside
24 for layer in range(n // 2):
25 # Define the boundaries of the current layer
26 first = layer
27 last = n - 1 - layer
28
29 # Rotate elements in the current layer
30 for i in range(first, last):
31 # Calculate offset from the start of the layer
32 offset = i - first
33
34 # Save top element
35 temp = matrix[first][i]
36
37 # Move left to top
38 matrix[first][i] = matrix[last - offset][first]
39
40 # Move bottom to left
41 matrix[last - offset][first] = matrix[last][last - offset]
42
43 # Move right to bottom
44 matrix[last][last - offset] = matrix[i][last]
45
46 # Move top (saved) to right
47 matrix[i][last] = temp
48
49 # Check all four possible rotations (0°, 90°, 180°, 270°)
50 for rotation_count in range(4):
51 # Check if current orientation matches target
52 if mat == target:
53 return True
54
55 # Rotate matrix 90 degrees clockwise for next check
56 rotate_90_clockwise(mat)
57
58 # No rotation matched the target
59 return False
60
1class Solution {
2 /**
3 * Determines if matrix 'mat' can be rotated (0, 90, 180, or 270 degrees clockwise)
4 * to match the 'target' matrix.
5 *
6 * @param mat The source matrix to rotate
7 * @param target The target matrix to match
8 * @return true if mat can be rotated to match target, false otherwise
9 */
10 public boolean findRotation(int[][] mat, int[][] target) {
11 // Check all 4 possible rotations (0°, 90°, 180°, 270°)
12 int rotationAttempts = 4;
13
14 while (rotationAttempts-- > 0) {
15 // Check if current rotation matches target
16 if (equals(mat, target)) {
17 return true;
18 }
19 // Rotate matrix 90 degrees clockwise for next check
20 rotate(mat);
21 }
22
23 return false;
24 }
25
26 /**
27 * Rotates the given square matrix 90 degrees clockwise in-place.
28 * Uses a layer-by-layer approach from outside to inside.
29 *
30 * @param matrix The matrix to rotate
31 */
32 private void rotate(int[][] matrix) {
33 int n = matrix.length;
34
35 // Process each layer from outer to inner
36 for (int layer = 0; layer < n / 2; ++layer) {
37 // Define the boundaries of current layer
38 int first = layer;
39 int last = n - 1 - layer;
40
41 // Rotate elements in current layer
42 for (int offset = first; offset < last; ++offset) {
43 // Save top element
44 int temp = matrix[first][offset];
45
46 // Move left to top
47 matrix[first][offset] = matrix[n - offset - 1][first];
48
49 // Move bottom to left
50 matrix[n - offset - 1][first] = matrix[last][n - offset - 1];
51
52 // Move right to bottom
53 matrix[last][n - offset - 1] = matrix[offset][last];
54
55 // Move saved top to right
56 matrix[offset][last] = temp;
57 }
58 }
59 }
60
61 /**
62 * Checks if two matrices are identical.
63 *
64 * @param matrix1 The first matrix
65 * @param matrix2 The second matrix
66 * @return true if matrices are identical, false otherwise
67 */
68 private boolean equals(int[][] matrix1, int[][] matrix2) {
69 int n = matrix1.length;
70
71 // Compare each element
72 for (int row = 0; row < n; ++row) {
73 for (int col = 0; col < n; ++col) {
74 if (matrix1[row][col] != matrix2[row][col]) {
75 return false;
76 }
77 }
78 }
79
80 return true;
81 }
82}
83
1class Solution {
2public:
3 bool findRotation(vector<vector<int>>& mat, vector<vector<int>>& target) {
4 int n = mat.size();
5
6 // Try all 4 possible rotations (0°, 90°, 180°, 270°)
7 for (int rotationCount = 0; rotationCount < 4; ++rotationCount) {
8 // Create a new matrix to store the rotated result
9 vector<vector<int>> rotatedMatrix(n, vector<int>(n));
10
11 // Perform 90-degree clockwise rotation
12 // For element at position (i, j) in original matrix,
13 // it moves to position (j, n-1-i) after rotation
14 for (int row = 0; row < n; ++row) {
15 for (int col = 0; col < n; ++col) {
16 rotatedMatrix[row][col] = mat[col][n - row - 1];
17 }
18 }
19
20 // Check if the rotated matrix matches the target
21 if (rotatedMatrix == target) {
22 return true;
23 }
24
25 // Update mat for the next rotation iteration
26 mat = rotatedMatrix;
27 }
28
29 // No rotation matched the target
30 return false;
31 }
32};
33
1/**
2 * Determines if matrix can be rotated (0°, 90°, 180°, or 270°) to match target matrix
3 * @param mat - The source matrix to rotate
4 * @param target - The target matrix to match
5 * @returns true if mat can be rotated to match target, false otherwise
6 */
7function findRotation(mat: number[][], target: number[][]): boolean {
8 // Try all 4 possible rotations (0°, 90°, 180°, 270°)
9 for (let rotationCount = 0; rotationCount < 4; rotationCount++) {
10 rotate(mat);
11
12 // Check if current rotation matches target
13 if (isEqual(mat, target)) {
14 return true;
15 }
16 }
17
18 return false;
19}
20
21/**
22 * Checks if two matrices are identical
23 * @param matrixA - First matrix to compare
24 * @param matrixB - Second matrix to compare
25 * @returns true if matrices are identical, false otherwise
26 */
27function isEqual(matrixA: number[][], matrixB: number[][]): boolean {
28 const size = matrixA.length;
29
30 // Compare each element
31 for (let row = 0; row < size; row++) {
32 for (let col = 0; col < size; col++) {
33 if (matrixA[row][col] !== matrixB[row][col]) {
34 return false;
35 }
36 }
37 }
38
39 return true;
40}
41
42/**
43 * Rotates a square matrix 90 degrees clockwise in-place
44 * Uses a four-way swap to rotate elements in groups of 4
45 * @param matrix - The matrix to rotate (modified in-place)
46 */
47function rotate(matrix: number[][]): void {
48 const size = matrix.length;
49
50 // Process matrix in layers from outside to inside
51 // Only need to process half the rows (rounded down)
52 for (let row = 0; row < size >> 1; row++) {
53 // Process half the columns (rounded up for odd-sized matrices)
54 for (let col = 0; col < (size + 1) >> 1; col++) {
55 // Perform 4-way swap for 90-degree rotation
56 // Each element moves to its clockwise position
57 [
58 matrix[row][col], // Top-left
59 matrix[size - 1 - col][row], // Bottom-left
60 matrix[size - 1 - row][size - 1 - col], // Bottom-right
61 matrix[col][size - 1 - row] // Top-right
62 ] = [
63 matrix[size - 1 - col][row], // Bottom-left → Top-left
64 matrix[size - 1 - row][size - 1 - col], // Bottom-right → Bottom-left
65 matrix[col][size - 1 - row], // Top-right → Bottom-right
66 matrix[row][col] // Top-left → Top-right
67 ];
68 }
69 }
70}
71
Time and Space Complexity
Time Complexity: O(n²)
The algorithm performs at most 4 rotations, and each rotation operation takes O(n²)
time where n
is the dimension of the square matrix.
Breaking down the rotation function:
- The outer loop runs
n/2
times (iterating through layers) - The inner loop runs approximately
n - 2i
times for each layeri
- The total number of elements processed is
n²/4
(since we process each element exactly once in a 90-degree rotation) - Each element swap operation takes
O(1)
time
The comparison mat == target
takes O(n²)
time as it needs to compare all n²
elements.
Since we perform at most 4 rotations and 4 comparisons, the total time complexity is 4 * O(n²) + 4 * O(n²) = O(n²)
.
Space Complexity: O(1)
The algorithm modifies the matrix in-place without using any additional data structures that scale with input size. Only a constant amount of extra space is used:
- The temporary variable
t
for swapping elements - Loop counters
i
andj
- The variable
n
storing the matrix dimension
Therefore, the space complexity is O(1)
(constant space).
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Modifying the Original Matrix
The most significant pitfall in this solution is that it modifies the input matrix mat
in-place during rotation. After the function executes, mat
will be left in a rotated state (potentially rotated up to 270 degrees), which can cause unexpected behavior if the caller expects the original matrix to remain unchanged.
Example of the problem:
mat = [[0,1],[1,0]]
target = [[1,0],[0,1]]
solution = Solution()
result = solution.findRotation(mat, target)
print(mat) # mat is now modified - could be [[1,0],[0,1]] instead of original
Solution: Create a deep copy of the matrix before performing rotations:
def findRotation(self, mat: List[List[int]], target: List[List[int]]) -> bool:
# Create a deep copy to avoid modifying the original
mat_copy = [row[:] for row in mat]
for _ in range(4):
if mat_copy == target:
return True
rotate_90_clockwise(mat_copy)
return False
2. Inefficient Comparison After Unnecessary Rotations
The current implementation always rotates the matrix even after the last comparison. If no match is found after checking all 4 orientations, the matrix gets rotated a 4th time unnecessarily (returning it to the original orientation, but still performing unnecessary work).
Solution: Check before rotating on the last iteration:
for i in range(4):
if mat == target:
return True
if i < 3: # Don't rotate after the last check
rotate_90_clockwise(mat)
return False
3. Alternative Mathematical Approach Overlooked
While the in-place rotation is space-efficient, for read-only operations or when preserving the original matrix is important, you could use index mapping without modifying the matrix:
Solution using index transformation:
def findRotation(self, mat: List[List[int]], target: List[List[int]]) -> bool:
n = len(mat)
# Check original orientation
if mat == target:
return True
# Check 90-degree rotation
if all(mat[n-1-j][i] == target[i][j] for i in range(n) for j in range(n)):
return True
# Check 180-degree rotation
if all(mat[n-1-i][n-1-j] == target[i][j] for i in range(n) for j in range(n)):
return True
# Check 270-degree rotation
if all(mat[j][n-1-i] == target[i][j] for i in range(n) for j in range(n)):
return True
return False
This approach avoids matrix modification entirely and can be more efficient for large matrices since it can short-circuit as soon as a mismatch is found.
What's the output of running the following function using input 56
?
1KEYBOARD = {
2 '2': 'abc',
3 '3': 'def',
4 '4': 'ghi',
5 '5': 'jkl',
6 '6': 'mno',
7 '7': 'pqrs',
8 '8': 'tuv',
9 '9': 'wxyz',
10}
11
12def letter_combinations_of_phone_number(digits):
13 def dfs(path, res):
14 if len(path) == len(digits):
15 res.append(''.join(path))
16 return
17
18 next_number = digits[len(path)]
19 for letter in KEYBOARD[next_number]:
20 path.append(letter)
21 dfs(path, res)
22 path.pop()
23
24 res = []
25 dfs([], res)
26 return res
27
1private static final Map<Character, char[]> KEYBOARD = Map.of(
2 '2', "abc".toCharArray(),
3 '3', "def".toCharArray(),
4 '4', "ghi".toCharArray(),
5 '5', "jkl".toCharArray(),
6 '6', "mno".toCharArray(),
7 '7', "pqrs".toCharArray(),
8 '8', "tuv".toCharArray(),
9 '9', "wxyz".toCharArray()
10);
11
12public static List<String> letterCombinationsOfPhoneNumber(String digits) {
13 List<String> res = new ArrayList<>();
14 dfs(new StringBuilder(), res, digits.toCharArray());
15 return res;
16}
17
18private static void dfs(StringBuilder path, List<String> res, char[] digits) {
19 if (path.length() == digits.length) {
20 res.add(path.toString());
21 return;
22 }
23 char next_digit = digits[path.length()];
24 for (char letter : KEYBOARD.get(next_digit)) {
25 path.append(letter);
26 dfs(path, res, digits);
27 path.deleteCharAt(path.length() - 1);
28 }
29}
30
1const KEYBOARD = {
2 '2': 'abc',
3 '3': 'def',
4 '4': 'ghi',
5 '5': 'jkl',
6 '6': 'mno',
7 '7': 'pqrs',
8 '8': 'tuv',
9 '9': 'wxyz',
10}
11
12function letter_combinations_of_phone_number(digits) {
13 let res = [];
14 dfs(digits, [], res);
15 return res;
16}
17
18function dfs(digits, path, res) {
19 if (path.length === digits.length) {
20 res.push(path.join(''));
21 return;
22 }
23 let next_number = digits.charAt(path.length);
24 for (let letter of KEYBOARD[next_number]) {
25 path.push(letter);
26 dfs(digits, path, res);
27 path.pop();
28 }
29}
30
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!