A 3 x 3
magic square is a 3 x 3
grid filled with distinct numbers from 1 to 9 such that each row, column, and both diagonals all have the same sum.
Given a row x col
grid
of integers, how many 3 x 3
contiguous magic square subgrids are there?
Note: while a magic square can only contain numbers from 1 to 9, grid
may contain numbers up to 15.
Example 1:
Input: grid = [[4,3,8,4],[9,5,1,9],[2,7,6,2]] Output: 1 Explanation: The following subgrid is a 3 x 3 magic square:while this one is not:
In total, there is only one magic square inside the given grid.
Example 2:
Input: grid = [[8]] Output: 0
Constraints:
row == grid.length
col == grid[i].length
1 <= row, col <= 10
0 <= grid[i][j] <= 15
Approach 01:
Time Complexity
-
C++
-
Python
#include <vector> #include <algorithm> using namespace std; class Solution { public: int numMagicSquaresInside(vector<vector<int>>& grid) { int magicSquareCount = 0; // Traverse through the grid, considering each 3x3 section for (int row = 0; row + 2 < grid.size(); ++row) { for (int col = 0; col + 2 < grid[0].size(); ++col) { if (isMagicSquare(grid, row, col)) { ++magicSquareCount; } } } return magicSquareCount; } private: // Function to check if a 3x3 section starting at (row, col) is a magic square bool isMagicSquare(const vector<vector<int>>& grid, int row, int col) { // Check that all values are between 1 and 9 and unique vector<int> digits(10, 0); for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { int value = grid[row + i][col + j]; if (value < 1 || value > 9 || ++digits[value] > 1) { return false; } } } // Check the sums of the rows, columns, and diagonals int sum1 = grid[row][col] + grid[row][col + 1] + grid[row][col + 2]; int sum2 = grid[row + 1][col] + grid[row + 1][col + 1] + grid[row + 1][col + 2]; int sum3 = grid[row + 2][col] + grid[row + 2][col + 1] + grid[row + 2][col + 2]; int sum4 = grid[row][col] + grid[row + 1][col] + grid[row + 2][col]; int sum5 = grid[row][col + 1] + grid[row + 1][col + 1] + grid[row + 2][col + 1]; int sum6 = grid[row][col + 2] + grid[row + 1][col + 2] + grid[row + 2][col + 2]; int diagonal1 = grid[row][col] + grid[row + 1][col + 1] + grid[row + 2][col + 2]; int diagonal2 = grid[row][col + 2] + grid[row + 1][col + 1] + grid[row + 2][col]; // Return true if all sums are equal return (sum1 == sum2 && sum2 == sum3 && sum3 == sum4 && sum4 == sum5 && sum5 == sum6 && sum6 == diagonal1 && diagonal1 == diagonal2); } };
class Solution: def numMagicSquaresInside(self, grid): magicSquareCount = 0 # Traverse through the grid, considering each 3x3 section for row in range(len(grid) - 2): for col in range(len(grid[0]) - 2): if self.isMagicSquare(grid, row, col): magicSquareCount += 1 return magicSquareCount # Function to check if a 3x3 section starting at (row, col) is a magic square def isMagicSquare(self, grid, row, col): # Check that all values are between 1 and 9 and unique digits = [0] * 10 for i in range(3): for j in range(3): value = grid[row + i][col + j] if value < 1 or value > 9 or digits[value] > 0: return False digits[value] += 1 # Check the sums of the rows, columns, and diagonals sum1 = grid[row][col] + grid[row][col + 1] + grid[row][col + 2] sum2 = grid[row + 1][col] + grid[row + 1][col + 1] + grid[row + 1][col + 2] sum3 = grid[row + 2][col] + grid[row + 2][col + 1] + grid[row + 2][col + 2] sum4 = grid[row][col] + grid[row + 1][col] + grid[row + 2][col] sum5 = grid[row][col + 1] + grid[row + 1][col + 1] + grid[row + 2][col + 1] sum6 = grid[row][col + 2] + grid[row + 1][col + 2] + grid[row + 2][col + 2] diagonal1 = grid[row][col] + grid[row + 1][col + 1] + grid[row + 2][col + 2] diagonal2 = grid[row][col + 2] + grid[row + 1][col + 1] + grid[row + 2][col] # Return true if all sums are equal return (sum1 == sum2 and sum2 == sum3 and sum3 == sum4 and sum4 == sum5 and sum5 == sum6 and sum6 == diagonal1 and diagonal1 == diagonal2)
- Grid Traversal:
The algorithm traverses the grid to check each possible 3×3 sub-grid. If the grid has dimensions \( m \times n \), there are approximately \( (m-2) \times (n-2) \) 3×3 sub-grids to check. Therefore, the time complexity for grid traversal is \( O(m \times n) \).
- Checking Magic Square:
For each 3×3 sub-grid, the algorithm checks if it forms a magic square. The number of operations for this check is constant (independent of \( m \) and \( n \)), so the time complexity of this check is \( O(1) \).
- Total Time Complexity:
The overall time complexity of the algorithm is \( O(m \times n) \), where \( m \) is the number of rows and \( n \) is the number of columns in the grid.
Space Complexity
- Auxiliary Space:
The algorithm uses an auxiliary vector of size 10 to check the uniqueness of digits in the 3×3 sub-grid, which requires \( O(1) \) space. Additionally, a few integer variables are used to store intermediate results, which also require \( O(1) \) space.
- Overall Space Complexity:
The overall space complexity of the algorithm is \( O(1) \), as it does not depend on the size of the input grid and only uses a constant amount of extra space.
Approach 02:
-
C++
-
Python
#include <vector> #include <string> #include <algorithm> using namespace std; class Solution { public: int numMagicSquaresInside(vector<vector<int>>& grid) { int magicSquareCount = 0; // Traverse through the grid, considering each 3x3 section for (int row = 0; row + 2 < grid.size(); ++row) { for (int col = 0; col + 2 < grid[0].size(); ++col) { // Check for basic properties: the center of the magic square must be 5 if (grid[row][col] % 2 == 0 && grid[row + 1][col + 1] == 5) { magicSquareCount += isMagicSquare(grid, row, col); } } } return magicSquareCount; } private: // Function to check if a 3x3 section starting at (row, col) is a magic square int isMagicSquare(const vector<vector<int>>& grid, int row, int col) { string squarePattern; // Construct a string pattern based on the elements' positions in the grid for (const int position : {0, 1, 2, 5, 8, 7, 6, 3}) { squarePattern += to_string(grid[row + position / 3][col + position % 3]); } // Check if the pattern matches any of the two valid magic square patterns return string("4381672943816729").find(squarePattern) != string::npos || string("9276183492761834").find(squarePattern) != string::npos; } };
class Solution: def numMagicSquaresInside(self, grid): magicSquareCount = 0 # Traverse through the grid, considering each 3x3 section for row in range(len(grid) - 2): for col in range(len(grid[0]) - 2): # Check for basic properties: the center of the magic square must be 5 if grid[row][col] % 2 == 0 and grid[row + 1][col + 1] == 5: magicSquareCount += self.isMagicSquare(grid, row, col) return magicSquareCount # Function to check if a 3x3 section starting at (row, col) is a magic square def isMagicSquare(self, grid, row, col): squarePattern = "" # Construct a string pattern based on the elements' positions in the grid for position in [0, 1, 2, 5, 8, 7, 6, 3]: squarePattern += str(grid[row + position // 3][col + position % 3]) # Check if the pattern matches any of the two valid magic square patterns return "4381672943816729".find(squarePattern) != -1 or \ "9276183492761834".find(squarePattern) != -1
Time Complexity
- Grid Traversal:
The algorithm traverses each possible 3×3 section in the grid. If the grid has dimensions \( n \times m \), there are \( (n – 2) \times (m – 2) \) possible 3×3 sections. For each section, the algorithm checks if it forms a magic square. Therefore, the time complexity of the grid traversal is \( O((n – 2) \times (m – 2)) \).
- Magic Square Check:
For each 3×3 section, the `isMagicSquare` function constructs a string pattern and checks it against two possible valid patterns. This operation takes constant time \( O(1) \). Since this check is performed for each possible 3×3 section, the total time complexity remains \( O((n – 2) \times (m – 2)) \).
- Overall Time Complexity:
The overall time complexity of the algorithm is \( O((n – 2) \times (m – 2)) \), which simplifies to \( O(n \times m) \).
Space Complexity
- Result Storage:
The algorithm uses a single integer variable `magicSquareCount` to store the number of magic squares found. This requires \( O(1) \) space.
- String Pattern Construction:
In the `isMagicSquare` function, a string `squarePattern` is constructed for each 3×3 section. Since this string has a fixed length, the space required for it is constant \( O(1) \).
- Overall Space Complexity:
The overall space complexity of the algorithm is \( O(1) \), as it only uses a constant amount of extra space.