📖本篇内容:Leetcode每日一题 661. 图片平滑器 前缀和公式以及矩阵边界问题
📑 文章专栏:leetcode每日一题《打卡日常》
📆 最近更新:2022 年 3 月 23日 Leetcode每日一题 440. 字典序的第K小数字 无树似有树 学习解题思路(感谢 杨兴元 uu 和 Benhao总)
⭐算法仓库:小付的算法之路——Alascanfu-algorithm.git.io
🙊个人简介:一只二本院校在读的大三程序猿,本着注重基础,打卡算法,分享技术作为个人的经验总结性的博文博主,虽然可能有时会犯懒,但是还是会坚持下去的,如果你很喜欢博文的话,建议看下面一行~(疯狂暗示QwQ)
🌇 点赞 👍 收藏 ⭐留言 📝 一键三连 关爱程序猿,从你我做起
🙊写在前面🙊
今天是一道二维前缀和与矩阵边界组合问题,其实很容易想到二维前缀和公式求解
,但是不会Coding又是另一回事
。
题目
图像平滑器 是大小为 3 x 3 的过滤器,用于对图像的每个单元格平滑处理,平滑处理后单元格的值为该单元格的平均灰度。
每个单元格的 平均灰度 定义为:该单元格自身及其周围的 8 个单元格的平均值,结果需向下取整。(即,需要计算蓝色平滑器中 9 个单元格的平均值)。
如果一个单元格周围存在单元格缺失的情况,则计算平均灰度时不考虑缺失的单元格(即,需要计算红色平滑器中 4 个单元格的平均值)。
(给你一个表示图像灰度的 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
📝思路📝
本题考查知识点
- 思路:看到这种给定区间的二维矩阵求和问题一般都会想到
二维前缀和公式进行求解
,本题难点不只是这个二维前缀和公式的考察,同时也考察了矩阵边界的问题处理方式
,这里咱们利用图来进行求解,会更直观明了一点。图示之前我们先来理解题意,确立矩阵区间位置,也就是说需要求取哪个子矩阵的和。
根据上图大概就可以知道二维的前缀和公式
二维前缀和公式:
S [ i ] [ j ] = s [ i − 1 ] [ j ] + S [ i ] [ j − 1 ] − S [ i − 1 ] [ j − 1 ] + a [ i ] [ j ] S[i][j] = s[i-1][j] + S[i][j-1] - S[i-1][j-1] + a[i][j] S[i][j]=s[i−1][j]+S[i][j−1]−S[i−1][j−1]+a[i][j]
其中S[i] [j] 表示第 i 行 j 列组成的矩阵的前缀和
那么获得得到这个前缀和之后有啥用呢? 这就是用来求一个子矩阵的区间和的快速求解方式。
所以求矩阵区间和公式:
S
x
2
y
2
−
S
x
1
−
1
y
2
−
S
x
2
y
1
−
1
+
S
x
1
−
1
y
1
−
1
S_{x_2y_2} - S_{{x_{1-1}}{y_2}} - S_{{x_{2}}{y_{1-1}}} + S_{{x_{1-1}{y_{1-1}}}}
Sx2y2−Sx1−1y2−Sx2y1−1+Sx1−1y1−1
然后就是边界问题了。
- 需要注意的是我们针对每个点,需要考虑当前节点是否有
左节点 、上节点、下节点 、右节点,且不能跨界
。如果跨界就用边界计算 且不统计个数。
⭐代码实现⭐
前缀和求解
class Solution {
public int[][] imageSmoother(int[][] img) {
int m = img.length;
int n = img[0].length;
int[][] s = new int[m+1][n+1];
for (int i = 1 ; i<=m;i++){
for (int j = 1 ;j<=n;j++){
s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1]+img[i-1][j-1];
}
}
int [][] res = new int[m][n];
for (int i = 0;i<m;i++){
for (int j = 0 ; j<n;j++){
int left = Math.max(0,j-1);
int right = Math.min(n-1,j+1);
int top = Math.max(0,i-1);
int down = Math.min(m-1,i+1);
int cnt = (right - left + 1) * (down - top + 1);
int val = s[down+1][right+1] - s[top][right+1] - s[down+1][left] + s[top][left];
res[i][j] = val / cnt;
}
}
return res;
}
}
运行结果
前缀和
🙊写在最后🙊
2022- 3 - 24今天小付打卡了哦~
美好的日出 美好的山河
都因有你存在 而璀璨 耀眼