[LeetCode] Matrix 值修改系列,例题 Surrounded Regions,Set Matrix Zeroes
引言
Matrix内部的值修改严格来讲放在一个系列里不大合适,因为对于不同的问题,所用的算法和技巧可能完全不同,权且这样归类,以后需要时再拆分吧。
例题 1
Given a 2D board containing 'X' and 'O', capture all regions surrounded by 'X'.
A region is captured by flipping all 'O's into 'X's in that surrounded region.
For example,
X X X X
X O O X
X X O X
X O X X
After running your function, the board should be:
X X X X
X X X X
X X X X
X O X X
class Solution {
public:
void solve(vector<vector<char>> &board) {
}
};
这道题的思路应该比较容易想到:
遍历最外层一圈,如果有O,就把其相邻的也设置为O。接着遍历全矩阵,把内层O置为X。
但是这样做的问题遍历全矩阵时,分不清遇到的O是内层还是外层。
因此改进的方法是遍历最外层时,将O及其相邻的字符都设为"Y"。遍历全矩阵时,把"O"设置为X,把"Y"设置回"O"。
寻找O的邻居时,用的自然是BFS。每遇到一个O,就通过BFS将它以及邻居设置为"Y"
代码:
class Solution {
struct Point{
int h;
int v;
Point(int vp, int hp) : v(vp), h(hp) {};
};
public:
void BFS(int startH, int startW, vector<vector<char>> &board, queue<Point> que){
while(!que.empty()) que.pop();
int W = board[].size(), H = board.size();
Point p(startH, startW);
que.push(p);
while(!que.empty()){
Point cur = que.front();
que.pop();
board[cur.v][cur.h] = 'Y';
for(int i = ; i < ; i++){ //扫描四个方向上的邻居
if((cur.v+addV[i]) < H
&& (cur.h+addH[i]) < W
&& (cur.v+addV[i]) >=
&& (cur.h+addH[i]) >=
&& board[cur.v+addV[i]][cur.h+addH[i]] == 'O'){
que.push(Point(cur.v+addV[i], cur.h+addH[i]));
}
}
}
}
void solve(vector<vector<char>> &board) {
if(board.size() == || board[].size() == ) return;
int W = board[].size(), H = board.size();
queue<Point> que;
int i, j = ;
for(i = ; i < W; ++i){
if(board[][i] == 'O') BFS(, i, board, que);
if(H > && board[H-][i] == 'O') BFS(H-, i, board, que); //遇到'O',调用BFS
}
for(i = ; i < H; ++i){
if(board[i][] == 'O') BFS(i, , board, que);
if(W > && board[i][W-] == 'O') BFS(i, W-, board, que);
}
for(i = ; i < H; ++i){ //再次遍历全数组
for(j = ; j < W; ++j){
if(board[i][j] == 'O') board[i][j] = 'X';
if(board[i][j] == 'Y') board[i][j] = 'O';
}
}
}
private:
int addV[] = {, , -, };
int addH[] = {, , , -};
};
这样提交上去,超时。
有什么办法可以缩短时间呢?回想思路可以发现:每次遇到O,我们都调用一次BFS,每一次调用BFS,都需要清空队列que,然后再push。
为什么不把所有的BFS并为一次呢?每次遇到O,我们只向队列que中push当前O所在的Point,最后调用一次BFS集中处理que,其效果是完全一样的,但是时间上却省去了每次清空队列的时间。
代码:
class Solution {
struct Point{
int h;
int v;
Point(int vp, int hp) : v(vp), h(hp) {};
};
public:
void solve(vector<vector<char>> &board) {
if(board.size() == || board[].size() == ) return;
int W = board[].size(), H = board.size();
queue<Point> que;
int i, j = ;
for(i = ; i < W; ++i){
if(board[][i] == 'O') que.push(Point(, i));
if(H > && board[H-][i] == 'O') que.push(Point(H-, i)); //遇到O,只push,不再调用BFS
}
for(i = ; i < H; ++i){
if(board[i][] == 'O') que.push(Point(i, ));
if(W > && board[i][W-] == 'O') que.push(Point(i, W-)); //遇到O,只push,不再调用BFS
}
while(!que.empty()){ //调用BFS
Point cur = que.front();
que.pop();
board[cur.v][cur.h] = 'Y';
for(int i = ; i < ; i++){
if((cur.v+addV[i]) < H
&& (cur.h+addH[i]) < W
&& (cur.v+addV[i]) >=
&& (cur.h+addH[i]) >=
&& board[cur.v+addV[i]][cur.h+addH[i]] == 'O'){
que.push(Point(cur.v+addV[i], cur.h+addH[i]));
}
}
}
for(i = ; i < H; ++i){
for(j = ; j < W; ++j){
if(board[i][j] == 'O') board[i][j] = 'X';
if(board[i][j] == 'Y') board[i][j] = 'O';
}
}
}
private:
int addV[] = {, , -, };
int addH[] = {, , , -};
};
小结:
这种需要更改Matrix的值的题目,上面解法用到了很简单的技巧:“引入一个中间值 Y”,避免了混淆。
例题 2
Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place.
Could you devise a constant space solution?
class Solution {
public:
void setZeroes(vector<vector<int> > &matrix) {
}
};
这道题的困难之处在于“需要空间复杂度为常量”
有了上一题的启发,我们可以将0所在的行和列都设置为别的值X,最后将所有X设置为0。
但是这样做的弱点在于:
1. 每个元素都要被访问 >= 2次 (那些和0同行同列的元素被访问大于2次,那些不和0同行同列的元素被访问了2次)。
2. 如果题目改成vector<vector<bool> >,这种解法就失效了,因为没有第三个值可以引入。
如果空间复杂度要求是O(m+n)的话,我们会申明两个数组,分别来记录需要设为0的行号和列号。
进一步,如果如果空间复杂度要求是O(1),我们虽然不能申明新数组,但是我们能用第一行和第一列来标记那些需要置为0的行和列。
当遇到 matix[i][j] == 0时,将matix[0][j] 和 matrix[i][0] 置为 0。
第一遍遍历matrix结束后,将所记录的行和列置为0。
这样做需要注意:如果第一行或者第一列有0,需要额外记录。
代码:
class Solution {
public:
void setZeroes(vector<vector<int> > &matrix) {
if(matrix.size() == ) return;
if(matrix[].size() == ) return;
bool firstRowSet = false;
bool firstColSet = false;
int i, j;
for(i = ; i < matrix.size(); ++i){
for(j = ; j < matrix[i].size(); ++j){
if(matrix[i][j] == ){
if(i == ) firstRowSet = true;
if(j == ) firstColSet = true;
matrix[i][] = ;
matrix[][j] = ;
}
}
}
for(i = ; i < matrix.size(); ++i){
if(matrix[i][] == ){
for(j = ; j < matrix[i].size(); ++j)
matrix[i][j] = ;
}
}
for(j = ; j < matrix[].size(); ++j){
if(matrix[][j] == ){
for(i = ; i < matrix.size(); ++i)
matrix[i][j] = ;
}
}
if(firstRowSet)
for(j = ; j < matrix[].size(); ++j)
matrix[][j] = ;
if(firstColSet)
for(i = ; i < matrix.size(); ++i)
matrix[i][] = ;
}
};
[LeetCode] Matrix 值修改系列,例题 Surrounded Regions,Set Matrix Zeroes的更多相关文章
- [LeetCode] Surrounded Regions 包围区域
Given a 2D board containing 'X' and 'O', capture all regions surrounded by 'X'. A region is captured ...
- 验证LeetCode Surrounded Regions 包围区域的DFS方法
在LeetCode中的Surrounded Regions 包围区域这道题中,我们发现用DFS方法中的最后一个条件必须是j > 1,如下面的红色字体所示,如果写成j > 0的话无法通过OJ ...
- leetcode 200. Number of Islands 、694 Number of Distinct Islands 、695. Max Area of Island 、130. Surrounded Regions
两种方式处理已经访问过的节点:一种是用visited存储已经访问过的1:另一种是通过改变原始数值的值,比如将1改成-1,这样小于等于0的都会停止. Number of Islands 用了第一种方式, ...
- 【LeetCode】130. Surrounded Regions (2 solutions)
Surrounded Regions Given a 2D board containing 'X' and 'O', capture all regions surrounded by 'X'. A ...
- Leetcode之深度优先搜索(DFS)专题-130. 被围绕的区域(Surrounded Regions)
Leetcode之深度优先搜索(DFS)专题-130. 被围绕的区域(Surrounded Regions) 深度优先搜索的解题详细介绍,点击 给定一个二维的矩阵,包含 'X' 和 'O'(字母 O) ...
- [LeetCode] 130. Surrounded Regions 包围区域
Given a 2D board containing 'X' and 'O'(the letter O), capture all regions surrounded by 'X'. A regi ...
- 【leetcode】Surrounded Regions
Surrounded Regions Given a 2D board containing 'X' and 'O', capture all regions surrounded by 'X'. A ...
- LeetCode: Surrounded Regions 解题报告
Surrounded Regions Given a 2D board containing 'X' and 'O', capture all regions surrounded by 'X'. A ...
- LeetCode解题报告—— Sum Root to Leaf Numbers & Surrounded Regions & Single Number II
1. Sum Root to Leaf Numbers Given a binary tree containing digits from 0-9 only, each root-to-leaf p ...
随机推荐
- python3【基础】-文件操作
1. python对文件操作流程: 打开文件,得到文件句柄并赋值给一个变量 通过句柄对文件操作 关闭文件 现有如下文件: 昨夜寒蛩不住鸣. 惊回千里梦,已三更. 起来独自绕阶行. 人悄悄,帘外月胧明. ...
- 03 JAVA IO
java.io包中定义了多个流类型来实现输入输出功能,以不同的角度进行分类: 按数据流的方向不同可以分为输入流和输出流 按处理数据单位不通可以分为字节流和字符流 按照功能不同可以分为节点流和处理流 所 ...
- lintcode-463-整数排序
463-整数排序 给一组整数,按照升序排序,使用选择排序,冒泡排序,插入排序或者任何 O(n2) 的排序算法. 样例 对于数组 [3, 2, 1, 4, 5], 排序后为:[1, 2, 3, 4, 5 ...
- lintcode395-硬币排成线 II
395-硬币排成线 II 有 n 个不同价值的硬币排成一条线.两个参赛者轮流从左边依次拿走 1 或 2 个硬币,直到没有硬币为止.计算两个人分别拿到的硬币总价值,价值高的人获胜. 请判定 第一个玩家 ...
- ImportError: No module named examples.tutorials.mnist
Traceback (most recent call last): File "nearest_neighbor.py", line 14, in <module> ...
- python接口自动化测试框架实现之操作mysq数据库
python操作mysql数据库需要使用到mysqlclient库. 安装:pip install mysqlclient python连接mysql数据库分以下步骤: 1.与mysql建立连接: 2 ...
- Struts2文件的上传和下载实现
<一>简述: Struts2的文件上传其实也是通过拦截器来实现的,只是该拦截器定义为默认拦截器了,所以不用自己去手工配置,<interceptor name="fileUp ...
- Hibernate 中一级缓存和快照区的理解
刚刚开始的时候觉得这个快照区很难理解,在网上看了很多博客之后,开始明白了.我是结合 ADO.NET 理解的,在ADO.NET 中有一个类, 叫 SqlCommandBuilder,在我看来,他就是 A ...
- 【C++】C++ static关键字详解
static的作用 1.隐藏 当我们编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性,其他的源文件也能访问.如,我们有源文件source1.cpp定义了一个全局变量i和函数Fu ...
- python的N个小功能(连接数据库并下载相应位置的图片)
#################################################################################################### ...