Given a 2D integer matrix M representing the gray scale of an image, you need to design a smoother to make the gray scale of each cell becomes the average gray scale (rounding down) of all the 8 surrounding cells and itself. If a cell has less than 8 surrounding cells, then use as many as you can.
Example 1:
Input: [[1,1,1], [1,0,1], [1,1,1]] Output: [[0, 0, 0], [0, 0, 0], [0, 0, 0]] Explanation: For the point (0,0), (0,2), (2,0), (2,2): floor(3/4) = floor(0.75) = 0 For the point (0,1), (1,0), (1,2), (2,1): floor(5/6) = floor(0.83333333) = 0 For the point (1,1): floor(8/9) = floor(0.88888889) = 0
Note:
- The value in the given matrix is in the range of [0, 255].
- The length and width of the given matrix are in the range of [1, 150].
Idea 1. Bruteforce, it's straightforward with auxiliary space, loop the old value from the input matrix.
Time complexity: O(M * N)
Space complexity: O(M * N)
1 class Solution { 2 public int[][] imageSmoother(int[][] M) { 3 int M1 = M.length; 4 int N1 = M[0].length; 5 6 int[][] dirs = {{-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}}; 7 8 int[][] result = new int[M1][N1]; 9 for(int i = 0; i < M1; ++i) { 10 for(int j = 0; j < N1; ++j) { 11 int count = 0; 12 for(int[] d : dirs) { 13 int nextX = i + d[0]; 14 int nextY = j + d[1]; 15 if(nextX >= 0 && nextX < M1 && nextY >= 0 && nextY < N1) { 16 ++count; 17 result[i][j] += M[nextX][nextY]; 18 } 19 } 20 result[i][j] += M[i][j]; 21 result[i][j] /= (count + 1); 22 } 23 } 24 25 return result; 26 } 27 }
Another way to loop the negighbours, including itself
1 class Solution { 2 public int[][] imageSmoother(int[][] M) { 3 int M1 = M.length; 4 int N1 = M[0].length; 5 6 int[][] result = new int[M1][N1]; 7 for(int i = 0; i < M1; ++i) { 8 for(int j = 0; j < N1; ++j) { 9 int count = 0; 10 for(int nextR = i-1; nextR <= i+1; ++nextR) { 11 for(int nextC = j-1; nextC <= j+1; ++nextC) { 12 if(nextR >= 0 && nextR < M1 && nextC >= 0 && nextC < N1) { 13 ++count; 14 result[i][j] += M[nextR][nextC]; 15 } 16 } 17 } 18 result[i][j] /= count; 19 } 20 } 21 22 return result; 23 } 24 }
Idea 2. in-place calculation, keeping the old value and updated value in the same M[i][j], since old value M[i][j] is in the range [0, 255], which can be represented by 8 bits (2^8 -1 = 255), a integer has 32 bits, hence from left to right, the first 8 bits stores the old value, the second 8 bits stores the updated value, once all the calculation is done, remove the old value by shifting the integer 8 bits to the right.
Note: 0xFF = 255, F = 15 = 1111
Time complexity: O(M * N)
Space complexity: O(1)
1 class Solution { 2 public int[][] imageSmoother(int[][] M) { 3 int M1 = M.length; 4 int N1 = M[0].length; 5 6 int mask = 0xFF; 7 for(int i = 0; i < M1; ++i) { 8 for(int j = 0; j < N1; ++j) { 9 int count = 0; 10 int sum = 0; 11 12 for(int nextR = i-1; nextR <= i+1; ++nextR) { 13 for(int nextC = j-1; nextC <= j+1; ++nextC) { 14 if(nextR >= 0 && nextR < M1 && nextC >= 0 && nextC < N1) { 15 ++count; 16 sum += (M[nextR][nextC] & mask); 17 } 18 } 19 } 20 21 M[i][j] |= (sum/count) << 8; 22 } 23 } 24 25 for(int i = 0; i < M1; ++i) { 26 for(int j = 0; j < N1; ++j) { 27 M[i][j] >>= 8; 28 } 29 } 30 31 return M; 32 } 33 }