3127. Make a Square with the Same Color
Problem Description
You are given a 3×3 grid filled with characters 'B' (representing black color) and 'W' (representing white color).
Your goal is to determine if you can create a 2×2 square where all four cells have the same color by changing the color of at most one cell in the grid.
The task asks you to:
- Look at the given 3×3 grid
- Check if there exists any 2×2 square within this grid that either:
- Already has all four cells of the same color, OR
- Can have all four cells of the same color after changing at most one cell
Return true
if such a 2×2 square of uniform color can be created, otherwise return false
.
For example, in a 3×3 grid, there are four possible 2×2 squares:
- Top-left corner (cells at positions [0,0], [0,1], [1,0], [1,1])
- Top-right corner (cells at positions [0,1], [0,2], [1,1], [1,2])
- Bottom-left corner (cells at positions [1,0], [1,1], [2,0], [2,1])
- Bottom-right corner (cells at positions [1,1], [1,2], [2,1], [2,2])
If any of these 2×2 squares has at least 3 cells of the same color (meaning you'd need to change at most 1 cell to make all 4 uniform), then the answer is true
.
Intuition
The key insight is that we only need to check each possible 2×2 square within the 3×3 grid. Since we can change at most one cell, a 2×2 square can be made uniform if it has at least 3 cells of the same color.
Think about it this way: in any 2×2 square (which has 4 cells total), the possible distributions of colors are:
- 4 cells of one color, 0 of the other → already uniform
- 3 cells of one color, 1 of the other → can change the 1 different cell to make it uniform
- 2 cells of each color → would need to change 2 cells to make it uniform (not allowed)
So the question becomes: does any 2×2 square in our grid have an unequal distribution of 'B' and 'W'?
If we count the number of 'B' cells and 'W' cells in a 2×2 square:
- If
count('B') ≠ count('W')
, then one color appears more than the other, meaning we have either a 3-1 or 4-0 distribution, both of which work - If
count('B') = count('W')
, then we have a 2-2 distribution, which doesn't work
Therefore, we can iterate through all four possible 2×2 squares in the 3×3 grid, count the occurrences of each color, and if any square has unequal counts, we return true
. If all squares have equal counts (2-2 distribution), we return false
.
The solution cleverly uses pairwise
to iterate through the four corners of each 2×2 square in a circular manner, counting both colors and checking if their counts differ.
Solution Approach
The solution uses a nested loop to check all possible 2×2 squares within the 3×3 grid.
Step 1: Iterate through starting positions
for i in range(0, 2):
for j in range(0, 2):
We only need i
and j
to go from 0 to 1 (not 2) because these represent the top-left corner of each 2×2 square. Starting from position (i, j)
, we can form a 2×2 square with corners at (i, j)
, (i, j+1)
, (i+1, j)
, and (i+1, j+1)
.
Step 2: Count colors in each 2×2 square
For each starting position, we need to visit the four cells of the 2×2 square. The solution uses a clever technique with pairwise
:
for a, b in pairwise((0, 0, 1, 1, 0)): x, y = i + a, j + b
The pairwise((0, 0, 1, 1, 0))
generates pairs: (0,0)
, (0,1)
, (1,1)
, (1,0)
. When added to the base position (i, j)
, these offsets give us the four corners of the 2×2 square in a circular order:
(i+0, j+0)
→ top-left(i+0, j+1)
→ top-right(i+1, j+1)
→ bottom-right(i+1, j+0)
→ bottom-left
Step 3: Count occurrences of each color
cnt1 += grid[x][y] == "W" cnt2 += grid[x][y] == "B"
For each cell in the 2×2 square, we increment cnt1
if it's white and cnt2
if it's black.
Step 4: Check if the square can be made uniform
if cnt1 != cnt2: return True
If the counts are not equal, it means we have either:
- 3 whites and 1 black (can change the black to white)
- 1 white and 3 blacks (can change the white to black)
- 4 of the same color (already uniform)
Any of these cases allows us to create a uniform 2×2 square with at most one change.
Step 5: Return false if no valid square found If we've checked all four possible 2×2 squares and none had unequal color counts (all were 2-2 splits), then it's impossible to create a uniform square with at most one change.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through an example with the following 3×3 grid:
W B W B W B W B W
Step 1: Check the top-left 2×2 square (i=0, j=0)
- Cells: [0,0]='W', [0,1]='B', [1,0]='B', [1,1]='W'
- Count: 2 whites, 2 blacks
- Since cnt1 == cnt2 (both are 2), we cannot make this uniform with ≤1 change
Step 2: Check the top-right 2×2 square (i=0, j=1)
- Cells: [0,1]='B', [0,2]='W', [1,1]='W', [1,2]='B'
- Count: 2 whites, 2 blacks
- Since cnt1 == cnt2 (both are 2), we cannot make this uniform with ≤1 change
Step 3: Check the bottom-left 2×2 square (i=1, j=0)
- Cells: [1,0]='B', [1,1]='W', [2,0]='W', [2,1]='B'
- Count: 2 whites, 2 blacks
- Since cnt1 == cnt2 (both are 2), we cannot make this uniform with ≤1 change
Step 4: Check the bottom-right 2×2 square (i=1, j=1)
- Cells: [1,1]='W', [1,2]='B', [2,1]='B', [2,2]='W'
- Count: 2 whites, 2 blacks
- Since cnt1 == cnt2 (both are 2), we cannot make this uniform with ≤1 change
Result: Return false
- no 2×2 square can be made uniform with at most one change.
Now let's try a different example where the answer is true
:
W B W B B B W B W
Step 1: Check the top-left 2×2 square (i=0, j=0)
- Cells: [0,0]='W', [0,1]='B', [1,0]='B', [1,1]='B'
- Count: 1 white, 3 blacks
- Since cnt1 ≠ cnt2 (1 ≠ 3), we can make this uniform by changing the one 'W' to 'B'
Result: Return true
immediately - we found a valid 2×2 square!
The key insight is that we only need to find ONE 2×2 square with unequal color distribution to return true
. In this case, changing cell [0,0] from 'W' to 'B' would create an all-black 2×2 square in the top-left corner.
Solution Implementation
1from typing import List
2from itertools import pairwise
3
4class Solution:
5 def canMakeSquare(self, grid: List[List[str]]) -> bool:
6 # Check all possible 2x2 squares in the grid
7 for row in range(2):
8 for col in range(2):
9 white_count = 0
10 black_count = 0
11
12 # Traverse the 2x2 square starting at (row, col)
13 # pairwise((0, 0, 1, 1, 0)) generates: (0,0), (0,1), (1,1), (1,0)
14 # This creates a clockwise traversal of the square corners
15 for delta_row, delta_col in pairwise((0, 0, 1, 1, 0)):
16 current_row = row + delta_row
17 current_col = col + delta_col
18
19 # Count white and black cells in the current 2x2 square
20 if grid[current_row][current_col] == "W":
21 white_count += 1
22 if grid[current_row][current_col] == "B":
23 black_count += 1
24
25 # If counts are unequal, we can form a valid square
26 # (either 3:1 or 4:0 ratio means one color dominates)
27 if white_count != black_count:
28 return True
29
30 # No valid 2x2 square found
31 return False
32
1class Solution {
2 public boolean canMakeSquare(char[][] grid) {
3 // Direction offsets to traverse a 2x2 square: (0,0), (0,1), (1,1), (1,0)
4 // Using pairs: (dirs[k], dirs[k+1]) for k = 0, 1, 2, 3
5 final int[] directions = {0, 0, 1, 1, 0};
6
7 // Check all possible 2x2 squares in the 3x3 grid
8 // There are 4 possible 2x2 squares with top-left corners at (0,0), (0,1), (1,0), (1,1)
9 for (int row = 0; row < 2; row++) {
10 for (int col = 0; col < 2; col++) {
11 int whiteCount = 0;
12 int blackCount = 0;
13
14 // Check all 4 cells in the current 2x2 square
15 for (int k = 0; k < 4; k++) {
16 int currentRow = row + directions[k];
17 int currentCol = col + directions[k + 1];
18
19 // Count white and black cells
20 if (grid[currentRow][currentCol] == 'W') {
21 whiteCount++;
22 } else {
23 blackCount++;
24 }
25 }
26
27 // If counts are unequal, we can make the square uniform with at most one change
28 // Possible scenarios: 3-1 or 4-0 split (can be made uniform with 1 or 0 changes)
29 if (whiteCount != blackCount) {
30 return true;
31 }
32 }
33 }
34
35 // All 2x2 squares have equal black and white cells (2-2 split)
36 // Would need 2 changes to make any square uniform
37 return false;
38 }
39}
40
1class Solution {
2public:
3 bool canMakeSquare(vector<vector<char>>& grid) {
4 // Direction array to traverse a 2x2 subgrid
5 // dirs[k] and dirs[k+1] form pairs: (0,0), (0,1), (1,1), (1,0)
6 // These represent relative positions in a 2x2 square
7 int directions[5] = {0, 0, 1, 1, 0};
8
9 // Iterate through all possible 2x2 subgrids in the 3x3 grid
10 // Starting positions are (0,0), (0,1), (1,0), (1,1)
11 for (int row = 0; row < 2; ++row) {
12 for (int col = 0; col < 2; ++col) {
13 int whiteCount = 0;
14 int blackCount = 0;
15
16 // Check all 4 cells in the current 2x2 subgrid
17 for (int k = 0; k < 4; ++k) {
18 // Calculate actual position in the grid
19 int currentRow = row + directions[k];
20 int currentCol = col + directions[k + 1];
21
22 // Count white and black cells
23 if (grid[currentRow][currentCol] == 'W') {
24 whiteCount++;
25 } else { // grid[currentRow][currentCol] == 'B'
26 blackCount++;
27 }
28 }
29
30 // If counts are unequal, we can make the 2x2 subgrid uniform
31 // by changing at most one cell (when count is 3:1 or 4:0)
32 if (whiteCount != blackCount) {
33 return true;
34 }
35 }
36 }
37
38 // No 2x2 subgrid can be made uniform with at most one change
39 return false;
40 }
41};
42
1/**
2 * Checks if we can make a 2x2 square of the same color by changing at most one cell
3 * @param grid - A 3x3 grid containing 'B' (black) or 'W' (white) cells
4 * @returns true if we can form a 2x2 square of same color, false otherwise
5 */
6function canMakeSquare(grid: string[][]): boolean {
7 // Direction array to iterate through 2x2 subgrid positions
8 // Represents: (0,0), (0,1), (1,1), (1,0) relative positions
9 const directions: number[] = [0, 0, 1, 1, 0];
10
11 // Check all possible 2x2 subgrids in the 3x3 grid
12 for (let row = 0; row < 2; row++) {
13 for (let col = 0; col < 2; col++) {
14 let whiteCount: number = 0;
15 let blackCount: number = 0;
16
17 // Check all 4 cells in the current 2x2 subgrid
18 for (let k = 0; k < 4; k++) {
19 const currentRow: number = row + directions[k];
20 const currentCol: number = col + directions[k + 1];
21
22 // Count white and black cells in the subgrid
23 if (grid[currentRow][currentCol] === 'W') {
24 whiteCount++;
25 } else {
26 blackCount++;
27 }
28 }
29
30 // If counts are unequal, we have 3:1 or 4:0 ratio
31 // This means we can form a 2x2 square of same color
32 if (whiteCount !== blackCount) {
33 return true;
34 }
35 }
36 }
37
38 return false;
39}
40
Time and Space Complexity
The time complexity is O(1)
. The code uses two nested loops that iterate from 0 to 1 (2 iterations each), creating a total of 4 iterations for the outer loops. For each of these 4 positions, it checks a 2×2 subgrid by iterating through 4 cells using the pairwise
function on the tuple (0, 0, 1, 1, 0)
, which generates 4 pairs: (0,0)
, (0,1)
, (1,1)
, (1,0)
. Therefore, the total number of operations is 4 × 4 = 16
, which is a constant number regardless of input size.
The space complexity is O(1)
. The algorithm only uses a constant amount of extra space for variables i
, j
, cnt1
, cnt2
, a
, b
, x
, and y
. The pairwise
function creates an iterator that generates pairs on-the-fly without storing all pairs in memory, so it doesn't contribute to additional space complexity. No data structures that grow with input size are created.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect Loop Bounds for Starting Positions
A common mistake is using range(3)
instead of range(2)
for the outer loops. This would attempt to create 2×2 squares starting from position (2,2), which would go out of bounds when trying to access cells at (3,3).
Incorrect:
for row in range(3): # Wrong! This tries to access grid[3][x]
for col in range(3): # Wrong! This tries to access grid[x][3]
Correct:
for row in range(2): # Correct - ensures 2x2 square stays within bounds
for col in range(2):
2. Misunderstanding the Problem - Checking Individual Cells Instead of 2×2 Squares
Some might interpret the problem as checking if any single cell can be changed to create some pattern, rather than specifically checking 2×2 squares.
Incorrect Approach:
# Wrong - just counting total colors in entire grid
total_white = sum(row.count('W') for row in grid)
total_black = sum(row.count('B') for row in grid)
Correct Approach: Check each of the four possible 2×2 squares individually.
3. Incorrect Color Counting Logic
Using the wrong condition to determine if a square can be made uniform. Remember that we need at least 3 cells of the same color (or all 4).
Incorrect:
if white_count >= 2 or black_count >= 2: # Wrong! A 2-2 split needs 2 changes return True
Correct:
if white_count != black_count: # This means 3-1 or 4-0, which is valid return True
4. Over-complicating the Traversal Pattern
While the pairwise
approach is elegant, it might be confusing. A simpler alternative that avoids this pitfall:
Alternative Clear Solution:
def canMakeSquare(self, grid: List[List[str]]) -> bool:
for row in range(2):
for col in range(2):
# Explicitly check all 4 cells in the 2x2 square
cells = [
grid[row][col], # top-left
grid[row][col+1], # top-right
grid[row+1][col], # bottom-left
grid[row+1][col+1] # bottom-right
]
white_count = cells.count('W')
black_count = cells.count('B')
# If we have 3 or 4 of the same color, we can make it uniform
if white_count >= 3 or black_count >= 3:
return True
return False
5. Forgetting Edge Cases
Not considering that a 2×2 square might already be uniform (all 4 cells same color), which requires zero changes and should return True
.
Solution: The condition white_count != black_count
correctly handles all cases:
- 4-0 or 0-4: Already uniform (0 changes needed)
- 3-1 or 1-3: Can be made uniform (1 change needed)
- 2-2: Cannot be made uniform with at most 1 change
Which type of traversal does breadth first search do?
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!