LeetCode 3030 - Find the Grid of Region Average
The problem gives us a grayscale image represented as an m x n matrix called image. Every value in the matrix is an integer between 0 and 255, representing the intensity of a pixel. We must examine every possible 3 x 3 subgrid inside the image.
Difficulty: 🟡 Medium
Topics: Array, Matrix
Solution
Problem Understanding
The problem gives us a grayscale image represented as an m x n matrix called image. Every value in the matrix is an integer between 0 and 255, representing the intensity of a pixel.
We must examine every possible 3 x 3 subgrid inside the image. A 3 x 3 subgrid is considered a valid region if every pair of adjacent cells inside that subgrid differs by at most threshold.
Adjacency here means sharing an edge, not a corner. Therefore, inside each 3 x 3 block we only need to check horizontal and vertical neighbors.
If a 3 x 3 block is valid:
- Compute the average of its 9 cells.
- Round that average down using integer division.
- Every cell belonging to this region receives that region average as a contribution.
A single pixel may belong to multiple valid regions because different 3 x 3 windows can overlap.
For every cell:
- If it belongs to one or more valid regions, its final value becomes the average of all contributing region averages, rounded down.
- If it belongs to no valid region, its value stays unchanged from the original image.
The constraints are important:
m, n <= 500- Total cells can be as large as
250,000
This means we must avoid expensive repeated computations. A solution with very high polynomial complexity would time out.
The important edge cases include:
- No valid regions at all, every cell remains unchanged.
- Every possible
3 x 3window is valid, many overlapping contributions occur. - Very small thresholds like
0, where only perfectly equal adjacent pixels can form a region. - Large thresholds like
255, where nearly every3 x 3window becomes valid. - Border cells that may belong to fewer regions than inner cells.
Approaches
Brute Force Approach
The brute force idea is straightforward:
- Enumerate every possible
3 x 3subgrid. - For each subgrid:
- Check all adjacent pairs.
- If valid, compute its average.
- For every valid region:
- Visit all 9 cells again and append the region average into a list for that cell.
- Finally:
-
For every cell:
-
If its list is empty, keep original value.
-
Otherwise compute the average of all stored region averages.
This approach is correct because it directly follows the problem definition.
However, storing lists of contributions for every cell is inefficient in both time and memory. Also, repeatedly managing dynamic lists creates unnecessary overhead.
Key Insight for the Optimal Solution
The important observation is that we do not actually need to store every contribution individually.
For each cell we only need:
- The sum of all contributing region averages
- The number of contributing regions
Then the final value is simply:
sum // count
This transforms the problem into an accumulation process.
Another key observation is that a 3 x 3 region contains only 12 adjacency checks:
- 6 horizontal edges
- 6 vertical edges
Since the region size is fixed, validating one region takes constant time.
The total number of possible 3 x 3 windows is:
(m - 2) * (n - 2)
So the entire algorithm becomes linear in the number of cells.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(m * n) | O(m * n * k) | Stores explicit contribution lists |
| Optimal | O(m * n) | O(m * n) | Uses running sums and counts |
Here, k represents the number of overlapping regions per cell.
Algorithm Walkthrough
- Create two auxiliary matrices:
region_sum[i][j], stores the total of all contributing region averagesregion_count[i][j], stores how many valid regions include the cell
- Iterate through every possible top-left corner of a
3 x 3window.
-
The top-left corner ranges from:
-
rows
0tom - 3 -
columns
0ton - 3
- For each
3 x 3window, validate whether it forms a region.
- Check every horizontal adjacent pair.
- Check every vertical adjacent pair.
- If any absolute difference exceeds
threshold, the region is invalid.
- If the region is valid:
- Compute the sum of all 9 cells.
- Compute the rounded-down average:
average = total // 9
- Add this region contribution to all 9 cells inside the region.
- Increment:
region_sum[r][c] += average
region_count[r][c] += 1
- After processing all regions, build the final result matrix.
-
For each cell:
-
If
region_count[i][j] == 0, use original image value. -
Otherwise:
result[i][j] = region_sum[i][j] // region_count[i][j]
Why it works
The algorithm works because every valid 3 x 3 region contributes exactly one rounded-down region average to each of its 9 cells. By accumulating the total contribution sum and contribution count separately, we preserve all information needed to compute the final rounded-down average for each cell. Since every region is checked exactly once and every valid contribution is added exactly once, the final matrix exactly matches the problem definition.
Python Solution
from typing import List
class Solution:
def resultGrid(self, image: List[List[int]], threshold: int) -> List[List[int]]:
rows = len(image)
cols = len(image[0])
region_sum = [[0] * cols for _ in range(rows)]
region_count = [[0] * cols for _ in range(rows)]
for top in range(rows - 2):
for left in range(cols - 2):
valid = True
# Check horizontal adjacent differences
for r in range(top, top + 3):
for c in range(left, left + 2):
if abs(image[r][c] - image[r][c + 1]) > threshold:
valid = False
break
if not valid:
break
# Check vertical adjacent differences
if valid:
for r in range(top, top + 2):
for c in range(left, left + 3):
if abs(image[r][c] - image[r + 1][c]) > threshold:
valid = False
break
if not valid:
break
if not valid:
continue
total = 0
for r in range(top, top + 3):
for c in range(left, left + 3):
total += image[r][c]
average = total // 9
for r in range(top, top + 3):
for c in range(left, left + 3):
region_sum[r][c] += average
region_count[r][c] += 1
result = [[0] * cols for _ in range(rows)]
for r in range(rows):
for c in range(cols):
if region_count[r][c] == 0:
result[r][c] = image[r][c]
else:
result[r][c] = (
region_sum[r][c] // region_count[r][c]
)
return result
The implementation closely follows the algorithm.
The first section initializes two matrices that track contribution totals and contribution counts. These matrices allow us to avoid storing individual lists of region averages.
The nested loops over top and left enumerate every possible 3 x 3 subgrid.
The validation phase checks horizontal and vertical neighboring cells separately. Early exits are used whenever an invalid adjacent pair is found, avoiding unnecessary work.
Once a region is confirmed valid, the code computes the region average using integer division. That average is then added to every cell inside the 3 x 3 block.
Finally, the result matrix is constructed. Cells with no contributions retain their original values, while cells with one or more contributions compute the rounded-down average of all region averages.
Go Solution
func resultGrid(image [][]int, threshold int) [][]int {
rows := len(image)
cols := len(image[0])
regionSum := make([][]int, rows)
regionCount := make([][]int, rows)
for i := 0; i < rows; i++ {
regionSum[i] = make([]int, cols)
regionCount[i] = make([]int, cols)
}
for top := 0; top < rows-2; top++ {
for left := 0; left < cols-2; left++ {
valid := true
// Horizontal checks
for r := top; r < top+3 && valid; r++ {
for c := left; c < left+2; c++ {
diff := image[r][c] - image[r][c+1]
if diff < 0 {
diff = -diff
}
if diff > threshold {
valid = false
break
}
}
}
// Vertical checks
for r := top; r < top+2 && valid; r++ {
for c := left; c < left+3; c++ {
diff := image[r][c] - image[r+1][c]
if diff < 0 {
diff = -diff
}
if diff > threshold {
valid = false
break
}
}
}
if !valid {
continue
}
total := 0
for r := top; r < top+3; r++ {
for c := left; c < left+3; c++ {
total += image[r][c]
}
}
average := total / 9
for r := top; r < top+3; r++ {
for c := left; c < left+3; c++ {
regionSum[r][c] += average
regionCount[r][c]++
}
}
}
}
result := make([][]int, rows)
for r := 0; r < rows; r++ {
result[r] = make([]int, cols)
for c := 0; c < cols; c++ {
if regionCount[r][c] == 0 {
result[r][c] = image[r][c]
} else {
result[r][c] = regionSum[r][c] / regionCount[r][c]
}
}
}
return result
}
The Go implementation mirrors the Python logic very closely.
Since Go does not provide a built-in absolute value function for integers without importing packages, the code computes absolute differences manually.
All matrices are initialized explicitly using nested make calls. Integer division in Go already performs floor division for positive numbers, which matches the problem requirements.
No special nil handling is required because the constraints guarantee valid input dimensions.
Worked Examples
Example 1
image =
[
[5, 6, 7, 10],
[8, 9, 10, 10],
[11, 12, 13, 10]
]
threshold = 3
Possible 3 x 3 windows:
| Top-left | Window |
|---|---|
| (0,0) | columns 0-2 |
| (0,1) | columns 1-3 |
Window 1, top-left (0,0)
Subgrid:
5 6 7
8 9 10
11 12 13
All adjacent differences are at most 3.
Region sum:
5+6+7+8+9+10+11+12+13 = 81
Region average:
81 // 9 = 9
All 9 cells receive contribution 9.
Window 2, top-left (0,1)
Subgrid:
6 7 10
9 10 10
12 13 10
All adjacent differences are at most 3.
Region sum:
6+7+10+9+10+10+12+13+10 = 87
Region average:
87 // 9 = 9
Now overlapping cells receive another contribution of 9.
Final averages become 9 everywhere.
Output:
[
[9,9,9,9],
[9,9,9,9],
[9,9,9,9]
]
Example 2
image =
[
[10,20,30],
[15,25,35],
[20,30,40],
[25,35,45]
]
There are two possible 3 x 3 windows.
First region
10 20 30
15 25 35
20 30 40
Sum:
225
Average:
25
Second region
15 25 35
20 30 40
25 35 45
Sum:
270
Average:
30
Rows 1 and 2 belong to both regions.
Combined value:
(25 + 30) // 2 = 27
Final result:
[
[25,25,25],
[27,27,27],
[27,27,27],
[30,30,30]
]
Example 3
image =
[
[5,6,7],
[8,9,10],
[11,12,13]
]
threshold = 1
Only one 3 x 3 window exists.
Check vertical adjacency:
|5 - 8| = 3
This exceeds the threshold.
Therefore no valid region exists.
All cells keep original values.
Output:
[
[5,6,7],
[8,9,10],
[11,12,13]
]
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(m * n) | Each 3 x 3 region requires constant work |
| Space | O(m * n) | Two auxiliary matrices are stored |
The total number of 3 x 3 windows is (m - 2) * (n - 2). Since each window performs only a fixed number of operations, validation and accumulation both take constant time per window. Therefore the total runtime is linear in the number of cells.
The extra memory comes from the region_sum and region_count matrices.
Test Cases
from typing import List
class Solution:
def resultGrid(self, image: List[List[int]], threshold: int) -> List[List[int]]:
rows = len(image)
cols = len(image[0])
region_sum = [[0] * cols for _ in range(rows)]
region_count = [[0] * cols for _ in range(rows)]
for top in range(rows - 2):
for left in range(cols - 2):
valid = True
for r in range(top, top + 3):
for c in range(left, left + 2):
if abs(image[r][c] - image[r][c + 1]) > threshold:
valid = False
break
if not valid:
break
if valid:
for r in range(top, top + 2):
for c in range(left, left + 3):
if abs(image[r][c] - image[r + 1][c]) > threshold:
valid = False
break
if not valid:
break
if not valid:
continue
total = 0
for r in range(top, top + 3):
for c in range(left, left + 3):
total += image[r][c]
avg = total // 9
for r in range(top, top + 3):
for c in range(left, left + 3):
region_sum[r][c] += avg
region_count[r][c] += 1
result = [[0] * cols for _ in range(rows)]
for r in range(rows):
for c in range(cols):
if region_count[r][c] == 0:
result[r][c] = image[r][c]
else:
result[r][c] = (
region_sum[r][c] // region_count[r][c]
)
return result
sol = Solution()
# Example 1
assert sol.resultGrid(
[[5,6,7,10],[8,9,10,10],[11,12,13,10]],
3
) == [
[9,9,9,9],
[9,9,9,9],
[9,9,9,9]
] # overlapping valid regions
# Example 2
assert sol.resultGrid(
[[10,20,30],[15,25,35],[20,30,40],[25,35,45]],
12
) == [
[25,25,25],
[27,27,27],
[27,27,27],
[30,30,30]
] # two stacked valid regions
# Example 3
assert sol.resultGrid(
[[5,6,7],[8,9,10],[11,12,13]],
1
) == [
[5,6,7],
[8,9,10],
[11,12,13]
] # no valid region
# Minimum size valid region
assert sol.resultGrid(
[[1,1,1],[1,1,1],[1,1,1]],
0
) == [
[1,1,1],
[1,1,1],
[1,1,1]
] # exactly one valid region
# Large threshold makes all regions valid
assert sol.resultGrid(
[[1,100,1],[100,1,100],[1,100,1]],
255
) == [
[45,45,45],
[45,45,45],
[45,45,45]
] # all differences allowed
# Single invalid edge ruins region
assert sol.resultGrid(
[[1,1,1],[1,100,1],[1,1,1]],
10
) == [
[1,1,1],
[1,100,1],
[1,1,1]
] # center creates invalid adjacency
# Multiple overlapping regions
assert sol.resultGrid(
[
[10,10,10,10],
[10,10,10,10],
[10,10,10,10],
[10,10,10,10]
],
0
) == [
[10,10,10,10],
[10,10,10,10],
[10,10,10,10],
[10,10,10,10]
] # every 3x3 window valid
| Test | Why |
|---|---|
| Example 1 | Verifies overlapping horizontal regions |
| Example 2 | Verifies vertically overlapping regions |
| Example 3 | Verifies behavior when no region is valid |
| Uniform 3x3 grid | Tests smallest valid configuration |
| Threshold 255 | Tests maximum threshold behavior |
| Invalid center spike | Ensures one bad edge invalidates region |
| Fully uniform 4x4 grid | Tests many overlapping valid regions |
Edge Cases
No Valid Regions
A common bug is incorrectly modifying cells even when no valid 3 x 3 region exists. In this situation every region_count[i][j] remains zero. The implementation explicitly checks for this and copies the original pixel value into the result.
Multiple Overlapping Regions
A pixel may belong to several valid regions simultaneously. Incorrect solutions sometimes overwrite values instead of accumulating them. This implementation uses separate sum and count matrices so every contribution is preserved correctly before the final averaging step.
Threshold Equal to Zero
When threshold = 0, every adjacent pair inside a valid region must have identical values. This can easily expose bugs in adjacency checking logic. The implementation checks all horizontal and vertical neighbor pairs independently, ensuring strict equality is enforced correctly.