The Image Smoother problem asks you to process a 2D integer matrix img
, representing a grayscale image, and return a new matrix of the same dimensions where each cell's value is replaced by the average (rounded down) of itself and all its valid neighbors. A neighbor is any cell that shares a side or corner with the current cell (up to 8 neighbors), but only those within the image boundaries are considered.
img
is not modified; you must return a new matrix.The task is to compute a "smoothed" value for every cell in the matrix by averaging it with its neighbors. The most direct approach is to, for each cell, examine all 8 possible neighbors (and itself), sum their values, count how many are valid (i.e., within bounds), and compute the floor of the average.
Initially, one might think about copying the matrix and for each cell, checking all directions, but this could be repetitive. Yet, since each cell is independent, and we must consider boundaries, a brute-force approach is reasonable here. We realize that more advanced optimizations (like prefix sums) are not necessary due to the small neighborhood (3x3) and the independence of calculations per cell.
The important insight is that for each cell, the set of neighbors is fixed in shape but variable in count (due to edges/corners). So, we must always check boundaries before including a neighbor in the sum.
Here’s a step-by-step breakdown of the solution:
img
to store the smoothed values.(i, j)
.(i, j)
(including itself).floor(sum / count)
.This approach is simple and robust, ensuring correctness for all matrix sizes and edge cases.
Consider the following input matrix:
img = [ [1, 1, 1], [1, 0, 1], [1, 1, 1] ]
Let's walk through the smoothing of the center cell (1, 1)
:
For a corner cell, say (0, 0)
:
Applying this to every cell, the output matrix becomes:
[ [0, 0, 0], [0, 0, 0], [0, 0, 0] ]
class Solution:
def imageSmoother(self, img):
m, n = len(img), len(img[0])
res = [[0] * n for _ in range(m)]
for i in range(m):
for j in range(n):
total = 0
count = 0
for x in range(i-1, i+2):
for y in range(j-1, j+2):
if 0 <= x < m and 0 <= y < n:
total += img[x][y]
count += 1
res[i][j] = total // count
return res
class Solution {
public:
vector<vector<int>> imageSmoother(vector<vector<int>>& img) {
int m = img.size(), n = img[0].size();
vector<vector<int>> res(m, vector<int>(n, 0));
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
int total = 0, count = 0;
for (int x = i - 1; x <= i + 1; ++x) {
for (int y = j - 1; y <= j + 1; ++y) {
if (x >= 0 && x < m && y >= 0 && y < n) {
total += img[x][y];
count++;
}
}
}
res[i][j] = total / count;
}
}
return res;
}
};
class Solution {
public int[][] imageSmoother(int[][] img) {
int m = img.length, n = img[0].length;
int[][] res = new int[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
int total = 0, count = 0;
for (int x = i - 1; x <= i + 1; x++) {
for (int y = j - 1; y <= j + 1; y++) {
if (x >= 0 && x < m && y >= 0 && y < n) {
total += img[x][y];
count++;
}
}
}
res[i][j] = total / count;
}
}
return res;
}
}
var imageSmoother = function(img) {
const m = img.length, n = img[0].length;
const res = Array.from({length: m}, () => Array(n).fill(0));
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
let total = 0, count = 0;
for (let x = i - 1; x <= i + 1; x++) {
for (let y = j - 1; y <= j + 1; y++) {
if (x >= 0 && x < m && y >= 0 && y < n) {
total += img[x][y];
count++;
}
}
}
res[i][j] = Math.floor(total / count);
}
}
return res;
};
Brute-force Approach:
The Image Smoother problem is elegantly solved by iterating over each cell and averaging the values of itself and its valid neighbors. The key insight is to carefully handle boundary conditions so that only valid indices are included in the average. The brute-force solution is optimal due to the fixed, small neighborhood size, and the approach is both intuitive and efficient for all practical input sizes.