Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

661. Image Smoother - Leetcode Solution

Problem Description

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.

  • Each cell in the output matrix must be the floor of the average of itself and its surrounding neighbors.
  • Edge and corner cells will have fewer than 8 neighbors, and you should only include valid positions in the average.
  • The input matrix img is not modified; you must return a new matrix.
  • Constraints ensure at least one row and one column.

Thought Process

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.

Solution Approach

Here’s a step-by-step breakdown of the solution:

  1. Initialize the Output Matrix:
    • Create a new matrix of the same size as img to store the smoothed values.
  2. Iterate Over Each Cell:
    • Use nested loops to visit every cell at position (i, j).
  3. Check All Neighbors:
    • For each cell, check all 9 positions in the 3x3 grid centered at (i, j) (including itself).
    • For each neighbor, check if its row and column indices are within the matrix boundaries.
  4. Compute the Average:
    • Sum the values of all valid neighbors (including itself) and count how many there are.
    • Set the output cell to floor(sum / count).
  5. Return the Output:
    • After processing all cells, return the output matrix.

This approach is simple and robust, ensuring correctness for all matrix sizes and edge cases.

Example Walkthrough

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):

  • Neighbors: all 9 cells (since it's not on an edge).
  • Sum: 1+1+1+1+0+1+1+1+1 = 8
  • Count: 9
  • Average: floor(8 / 9) = 0

For a corner cell, say (0, 0):

  • Valid neighbors: (0,0), (0,1), (1,0), (1,1)
  • Sum: 1+1+1+0 = 3
  • Count: 4
  • Average: floor(3 / 4) = 0

Applying this to every cell, the output matrix becomes:

    [
      [0, 0, 0],
      [0, 0, 0],
      [0, 0, 0]
    ]
  

Code Implementation

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;
};
      

Time and Space Complexity

Brute-force Approach:

  • Time Complexity: O(m * n), where m is the number of rows and n is the number of columns. For each cell, we check up to 9 positions (a constant), so the total work is proportional to the number of cells.
  • Space Complexity: O(m * n), since we create a new matrix of the same size for the output.
Optimized Approach:
  • In this problem, the brute-force approach is already optimal due to the small, fixed neighborhood and independence of each cell's calculation. More advanced optimizations (like prefix sum matrices) are unnecessary and would add overhead.

Summary

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.