本文已参与「新人创作礼」活动,一起开启掘金创作之路。
| 每日一题做题记录,参考官方和三叶的题解 |
题目要求
思路一:模拟
直接根据题目模拟。
Java
class Solution {
public int[][] imageSmoother(int[][] img) {
int m = img.length, n = img[0].length;
int[][] res = new int[m][n];
int[][] dirs = new int[][]{{-1,-1}, {-1,0}, {-1,1}, {0,-1}, {0,0}, {0,1}, {1,-1}, {1,0}, {1,1}};
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
int sum = 0, cnt = 0;
for(int[] d : dirs) {
int nx = i + d[0], ny = j + d[1];
if(nx < 0 || nx >= m || ny < 0 || ny >= n)
continue;
sum += img[nx][ny];
cnt++;
}
res[i][j] = sum / cnt;
}
}
return res;
}
}
- 时间复杂度:,为边数,为节点数,为灰度单位所包含的单元格数量,本题固定为9
- 空间复杂度:
C++
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));
int dirs[9][2] = {{-1,-1}, {-1,0}, {-1,1}, {0,-1}, {0,0}, {0,1}, {1,-1}, {1,0}, {1,1}};
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
int sum = 0, cnt = 0;
for(int k = 0; k < 9; k++) {
int nx = i + dirs[k][0], ny = j + dirs[k][1];
if(nx < 0 || nx >= m || ny < 0 || ny >= n)
continue;
sum += img[nx][ny];
cnt++;
}
res[i][j] = sum / cnt;
}
}
return res;
}
};
- 时间复杂度:
- 空间复杂度:
vector
- 学习参考链接
- 简介
- 一个封装了动态大小数组的顺序容器。
- 严格线性顺序排序;
- 动态数组快速访问操作;
- 使用内存分配器对象动态处理其存储需求。
- 代码中的
res:大小为的容器,每个元素又都是一个大小为的容器。
一个没什么必要的空间优化思路
用时间换空间,不定义dirs数组,而用两个for循环替代:
for (int x = i - 1; x <= i + 1; x++) {
for (int y = j - 1; y <= j + 1; y++) {
......
}
}
此时时间复杂度为。
思路二:前缀和
每次遍历周围的八个很明显会有大量重复,所以采用前缀和,提前计算每个元素左上矩阵之和,即从到所有值相加,即图示部分。
计算时则用右下元素的前缀减去多余值即可,即。
Java
class Solution {
public int[][] imageSmoother(int[][] img) {
int m = img.length, n = img[0].length;
int[][] prefix = new int[m + 10][n + 10];
for(int i = 1; i <= m; i++)
for(int 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];
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, i - 1), up = Math.max(0, j - 1);
int right = Math.min(m - 1, i + 1), down = Math.min(n - 1, j + 1);
int cnt = (right - left + 1) * (down - up + 1);
//右下角-左多余-上多余+左上角
int sum = prefix[right + 1][down + 1] - prefix[left][down + 1] - prefix[right + 1][up] + prefix[left][up];
res[i][j] = sum / cnt;
}
}
return res;
}
}
- 时间复杂度:
- 空间复杂度:
C++
class Solution {
public:
vector<vector<int>> imageSmoother(vector<vector<int>>& img) {
int m = img.size(), n = img[0].size();
vector<vector<int>> prefix(m + 10, vector<int>(n + 10));
for(int i = 1; i <= m; i++)
for(int 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];
vector<vector<int>> res(m, vector<int>(n));
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
//防止越界
int left = max(0, i - 1), up = max(0, j - 1);
int right = min(m - 1, i + 1), down = min(n - 1, j + 1);
int cnt = (right - left + 1) * (down - up + 1);
//右下角-左多余-上多余+左上角
int sum = prefix[right + 1][down + 1] - prefix[left][down + 1] - prefix[right + 1][up] + prefix[left][up];
res[i][j] = sum / cnt;
}
}
return res;
}
};
- 时间复杂度:
- 空间复杂度:
总结
本题实现很简单,对于法二,能够想到要用前缀和,但具体思路还是要经过一番推敲。
同时也要注意C++容器的使用。
如果了解深度学习的话,这道题其实是个平均池化,其padding 为 1,stride 为 1,核为 3×3。
| 欢迎指正与讨论! |