LeetCode打卡day24—— 图片平滑器

78 阅读3分钟

“Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情。”

一、题目描述:

661. 图片平滑器

图像平滑器 是大小为 3 x 3 的过滤器,用于对图像的每个单元格平滑处理,平滑处理后单元格的值为该单元格的平均灰度。

每个单元格的  平均灰度 定义为:该单元格自身及其周围的 8 个单元格的平均值,结果需向下取整。(即,需要计算蓝色平滑器中 9 个单元格的平均值)。

如果一个单元格周围存在单元格缺失的情况,则计算平均灰度时不考虑缺失的单元格(即,需要计算红色平滑器中 4 个单元格的平均值)。

image.png 给你一个表示图像灰度的 m x n 整数矩阵 img ,返回对图像的每个单元格平滑处理后的图像 。

示例 1:

输入:img = [[1,1,1],[1,0,1],[1,1,1]]
输出:[[0, 0, 0],[0, 0, 0], [0, 0, 0]]
解释:
对于点 (0,0), (0,2), (2,0), (2,2): 平均(3/4) = 平均(0.75) = 0
对于点 (0,1), (1,0), (1,2), (2,1): 平均(5/6) = 平均(0.83333333) = 0
对于点 (1,1): 平均(8/9) = 平均(0.88888889) = 0
示例 2:


输入: img = [[100,200,100],[200,50,200],[100,200,100]]
输出: [[137,141,137],[141,138,141],[137,141,137]]
解释:
对于点 (0,0), (0,2), (2,0), (2,2): floor((100+200+200+50)/4) = floor(137.5) = 137
对于点 (0,1), (1,0), (1,2), (2,1): floor((200+200+50+200+100+100)/6) = floor(141.666667) = 141
对于点 (1,1): floor((50+200+200+200+200+100+100+100+100)/9) = floor(138.888889) = 138
 

提示:

m == img.length
n == img[i].length
1 <= m, n <= 200
0 <= img[i][j] <= 255

二、思路分析:

  1. 直接模拟 用数组position表示周围八格的方向,遍历img每一位,计算数值
/**
 * @param {number[][]} img
 * @return {number[][]}
 */
var imageSmoother = function(img) {
    let position=[-1,0,-1,-1,-1,1,0,-1,0,1,1,-1,1,0,1,1]
    let m=img.length,n=img[0].length
    let newimg=new Array(m).fill(0).map(()=>new Array(n))
    for(let i=0;i<m;i++){
        for(let j=0;j<n;j++){
            let sum=img[i][j],num=1
            for(let p=0;p<position.length-1;p+=2){
                let x=i+position[p],y=j+position[p+1]
                if(x<0||y<0||x>=m||y>=n)continue
                else{
                    num++
                    sum+=img[x][y]
                }
            }
            newimg[i][j]=Math.floor(sum/num)
        }
    }
    return newimg
};
  1. 二维前缀和 我们发现要求的范围,就是一个矩形,当求值的点为i,j时,它的左上角为i-1,j-1,右下角为i+1,j+1,组成这个矩形。

我们用二维前缀和数组prefix表示从0,0到i,j的矩形的面积,公式为

prefix[i][j]=prefix[i-1][j]+prefix[i][j-1]-prefix[i-1][j-1]+img[i-1][j-1] 为了方便边界判断,prefix长度为img的长度+1,即prefix的第i,j表示img的i-1,j-1

我们如何使用前缀和?为了求矩阵,它的左上角为i-1,j-1,右下角为i+1,j+1,则求解公式为

prefix[maxx][maxy]-prefix[minx-1][maxy]-prefix[maxx][miny-1]+prefix[minx-1][miny-1]

代码如下

/**
 * @param {number[][]} img
 * @return {number[][]}
 */
var imageSmoother = function(img) {
    let m=img.length,n=img[0].length
    let prefix=new Array(m+1).fill(0).map(()=>new Array(n+1).fill(0))
    for(let i=1;i<=m;i++){
        for(let j=1;j<=n;j++){
            prefix[i][j]=prefix[i-1][j]+prefix[i][j-1]-prefix[i-1][j-1]+img[i-1][j-1]
        }
    }
    for(let i=1;i<=m;i++){
        for(let j=1;j<=n;j++){
            let minx=Math.max(i-1,1),miny=Math.max(1,j-1)
            let maxx=Math.min(m,i+1),maxy=Math.min(n,j+1)
            let num=(maxx-minx+1)*(maxy-miny+1)
           let value=prefix[maxx][maxy]-prefix[minx-1][maxy]-prefix[maxx][miny-1]+prefix[minx-1][miny-1]
           img[i-1][j-1]=Math.floor(value/num)
        }
    }
    return img
};