二维数组及滚动数组(二)
文章内容是自己刷leetcode官方刷题攻略的一些经验与总结。
题目链接详见 leetcode刷题攻略
如果喜欢的话,别忘了点个赞哦 ^ _ ^
一.661图片平滑器
1.题目描述
2.题目分析与解答
这道题目其实和计算机视觉里的kernel为3*3的均值滤波器类似。
当然不清楚均值滤波器也没关系。我们分析发现需要根据题目提供的矩阵来构造一个新矩阵,那么新矩阵的每个元素是怎么得到的呢?
新矩阵的每个元素与原矩阵对应位置及其周围8个单元格有关。有下面几种情况:
- 情况一:原矩阵周围8个单元格都有数值,也就是这8个单元格在原始矩阵边界范围内。这种情况下新矩阵的值就是原始矩阵对应位置的值及其周围8个单元格的值的和再除以9。
- 情况二:原矩阵周围8个单元格部分没有数值,也就是8个单元格中一部分在矩阵的边界内,一部分超出了矩阵的边界,这种情况下,新矩阵的值就是原始矩阵对应位置的值以及周围8个单元格中在边界范围内的单元格的值的和除以有效单元格的个数。
我们可以用num来统计有效单元格的个数,sum来统计有效单元格的数值和。
C++代码如下:
class Solution {
public:
vector<vector<int>> imageSmoother(vector<vector<int>>& img) {
//类似计算机视觉里面的均值滤波器,kernel为3*3
//遍历,判断边界就行
int m = img.size();
int n = img[0].size();
vector<vector<int>> ans(m, vector<int>(n, 0));
for(int i = 0; i < m; i ++) {
for(int j = 0; j < n; j ++) {
int num = 0, sum = 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) {
num ++;
sum += img[x][y];
}
}
}
ans[i][j] = sum / num;
}
}
return ans;
}
};
二.598范围求和II
1.题目描述
2.题目分析与解答
我们直接可以想到的方法是,先用题目提供的ops矩阵来把原始矩阵处理一遍,然后再次遍历处理后的矩阵,用maxNum来记录最大值,cnt记录最大值出现的个数。
C++ 代码如下:
class Solution {
public:
int maxCount(int m, int n, vector<vector<int>>& ops) {
//1.先根据ops处理矩阵
//2.再找最大整数个数
vector<vector<int>> matrix(m, vector<int>(n, 0));
for(int i = 0; i < ops.size(); i ++) {
int x = ops[i][0], y = ops[i][1];
for(int p = 0; p < x; p ++) {
for(int q = 0; q < y; q ++) {
matrix[p][q] ++;
}
}
}
int cnt = 0, maxNum = 0;
for(int i = 0; i < m; i ++) {
for(int j = 0; j < n; j ++) {
if(matrix[i][j] == maxNum) {
cnt ++;
} else if(matrix[i][j] > maxNum) {
cnt = 1;
maxNum = matrix[i][j];
}
}
}
return cnt;
}
};
很可惜,上述暴力的做法会超时。
我们可以分析一下时间复杂度,主要有两个大循环,那么就是取二者最大值。
第一个大循环最差情况为 ops 长度 * ops[i] 中每个元素的最大值。
所以时间复杂度为O(m * n * ops.length)。
第二个大循环为O(m * n)
那么显然第一个循环时间更长。
这道题其实我们可以转换思路:
矩阵中的数是通过ops二维数组才增加的,寻找矩阵中的最大整数,就是寻找哪些位置被操作的次数最多,也就是寻找ops数组中最小的两个ai,bi的乘积。
C++ 代码如下:
class Solution {
public:
int maxCount(int m, int n, vector<vector<int>>& ops) {
//1.先根据ops处理矩阵
//2.再找最大整数个数
//很可惜,上述做法会超时
//转换思路
//矩阵中的数是通过ops二维数组才增加的,寻找矩阵中的最大整数,就是寻找哪些位置被操作的次数最多,也就是寻找ops数组中最小的两个ai,bi的乘积
//转换思路
int minm = m, minn = n;
for(int i = 0; i < ops.size(); i ++) {
minm = min(minm, ops[i][0]);
minn = min(minn, ops[i][1]);
}
return minm * minn;
//超时方法
// vector<vector<int>> matrix(m, vector<int>(n, 0));
// for(int i = 0; i < ops.size(); i ++) {
// int x = ops[i][0], y = ops[i][1];
// for(int p = 0; p < x; p ++) {
// for(int q = 0; q < y; q ++) {
// matrix[p][q] ++;
// }
// }
// }
// int cnt = 0, maxNum = 0;
// for(int i = 0; i < m; i ++) {
// for(int j = 0; j < n; j ++) {
// if(matrix[i][j] == maxNum) {
// cnt ++;
// } else if(matrix[i][j] > maxNum) {
// cnt = 1;
// maxNum = matrix[i][j];
// }
// }
// }
// return cnt;
}
};
三.419甲板上的战舰
1.题目描述
2.题目分析与解答
这道题目中文翻译可能有歧义。
按照英文翻译,紧挨着的战舰battleship应该算作一个ships,我们最终需要统计ships的数量而不是battleship的数量。
1.解法一:更改 ‘X’ 为 ‘.’
遍历board遇到battleship就把与它在一个ships的battleship全变为 ‘.’,更新答案。
时间复杂度O(m * n * max(m,n))
C++ 代码如下:
class Solution {
public:
int countBattleships(vector<vector<char>>& board) {
//题目可能有歧义
//按照英文翻译,紧挨着的战舰battleship应该算作一个ships,统计ships的数量
int ans = 0;
int m = board.size();
int n = board[0].size();
for(int i = 0 ; i < m; i ++) {
for(int j = 0; j < n; j ++) {
if(board[i][j] == 'X') {
ans ++;
board[i][j] = '.';
for(int k = i + 1; k < m && board[k][j] == 'X'; k ++) {
board[k][j] = '.';
}
for(int k = j + 1; k < n && board[i][k] == 'X'; k ++) {
board[i][k] = '.';
}
}
}
}
return ans;
}
};
2.解法二:实现一次扫描算法,并只使用 O(1) 额外空间,并且不修改 board 的值
枚举起点,只在X刚出现的位置统计个数,枚举左和上方(为了避免重复,左右和上下两者中各选一个即可)。
如果当前位置为 ‘X’,判断当前位置的左方和上方,如果两者之一出现过 ‘X’,说明在之前已经统计过该battleship了,他们属于一个ships。我们只统计每个ships中的第一个battleship,其余的battleship就跳过,避免重复。
时间复杂度O(m * n)
C ++ 代码如下:
class Solution {
public:
int countBattleships(vector<vector<char>>& board) {
//题目可能有歧义
//按照英文翻译,紧挨着的战舰battleship应该算作一个ships,统计ships的数量
//遍历board遇到battleship就把与它在一个ships的battleship全变为'.',更新答案
//时间复杂度O(m * n * max(m,n))
//方法二O(m * n) 且不改变board的值
//枚举起点,只在X刚出现的位置统计个数,枚举左和上方
int ans = 0;
int m = board.size();
int n = board[0].size();
for(int i = 0; i < m; i ++) {
for(int j = 0 ; j < n ; j ++) {
if(board[i][j] == 'X') {
if(i > 0 && board[i - 1][j] == 'X') continue; //上
if(j > 0 && board[i][j - 1] == 'X') continue; //左
ans ++;
}
}
}
return ans;
//方法一
// int ans = 0;
// int m = board.size();
// int n = board[0].size();
// for(int i = 0 ; i < m; i ++) {
// for(int j = 0; j < n; j ++) {
// if(board[i][j] == 'X') {
// ans ++;
// board[i][j] = '.';
// for(int k = i + 1; k < m && board[k][j] == 'X'; k ++) {
// board[k][j] = '.';
// }
// for(int k = j + 1; k < n && board[i][k] == 'X'; k ++) {
// board[i][k] = '.';
// }
// }
// }
// }
// return ans;
}
};