引言

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,

  1. X X X X
  2. X O O X
  3. X X O X
  4. X O X X

After running your function, the board should be:

  1. X X X X
  2. X X X X
  3. X X X X
  4. X O X X
  1. class Solution {
  2. public:
  3. void solve(vector<vector<char>> &board) {
  4. }
  5. };

这道题的思路应该比较容易想到:

遍历最外层一圈,如果有O,就把其相邻的也设置为O。接着遍历全矩阵,把内层O置为X。

但是这样做的问题遍历全矩阵时,分不清遇到的O是内层还是外层。

因此改进的方法是遍历最外层时,将O及其相邻的字符都设为"Y"。遍历全矩阵时,把"O"设置为X,把"Y"设置回"O"。

寻找O的邻居时,用的自然是BFS。每遇到一个O,就通过BFS将它以及邻居设置为"Y"

代码:

  1. class Solution {
  2. struct Point{
  3. int h;
  4. int v;
  5. Point(int vp, int hp) : v(vp), h(hp) {};
  6. };
  7. public:
  8. void BFS(int startH, int startW, vector<vector<char>> &board, queue<Point> que){
  9. while(!que.empty()) que.pop();
  10. int W = board[].size(), H = board.size();
  11. Point p(startH, startW);
  12. que.push(p);
  13. while(!que.empty()){
  14. Point cur = que.front();
  15. que.pop();
  16. board[cur.v][cur.h] = 'Y';
  17. for(int i = ; i < ; i++){ //扫描四个方向上的邻居
  18. if((cur.v+addV[i]) < H
  19. && (cur.h+addH[i]) < W
  20. && (cur.v+addV[i]) >=
  21. && (cur.h+addH[i]) >=
  22. && board[cur.v+addV[i]][cur.h+addH[i]] == 'O'){
  23. que.push(Point(cur.v+addV[i], cur.h+addH[i]));
  24. }
  25. }
  26. }
  27. }
  28.  
  29. void solve(vector<vector<char>> &board) {
  30. if(board.size() == || board[].size() == ) return;
  31. int W = board[].size(), H = board.size();
  32. queue<Point> que;
  33. int i, j = ;
  34. for(i = ; i < W; ++i){
  35. if(board[][i] == 'O') BFS(, i, board, que);
  36. if(H > && board[H-][i] == 'O') BFS(H-, i, board, que); //遇到'O',调用BFS
  37. }
  38. for(i = ; i < H; ++i){
  39. if(board[i][] == 'O') BFS(i, , board, que);
  40. if(W > && board[i][W-] == 'O') BFS(i, W-, board, que);
  41. }
  42.  
  43. for(i = ; i < H; ++i){ //再次遍历全数组
  44. for(j = ; j < W; ++j){
  45. if(board[i][j] == 'O') board[i][j] = 'X';
  46. if(board[i][j] == 'Y') board[i][j] = 'O';
  47. }
  48. }
  49. }
  50. private:
  51. int addV[] = {, , -, };
  52. int addH[] = {, , , -};
  53. };

这样提交上去,超时。

有什么办法可以缩短时间呢?回想思路可以发现:每次遇到O,我们都调用一次BFS,每一次调用BFS,都需要清空队列que,然后再push。

为什么不把所有的BFS并为一次呢?每次遇到O,我们只向队列que中push当前O所在的Point,最后调用一次BFS集中处理que,其效果是完全一样的,但是时间上却省去了每次清空队列的时间。

代码:

  1. class Solution {
  2. struct Point{
  3. int h;
  4. int v;
  5. Point(int vp, int hp) : v(vp), h(hp) {};
  6. };
  7. public:
  8. void solve(vector<vector<char>> &board) {
  9. if(board.size() == || board[].size() == ) return;
  10. int W = board[].size(), H = board.size();
  11. queue<Point> que;
  12. int i, j = ;
  13. for(i = ; i < W; ++i){
  14. if(board[][i] == 'O') que.push(Point(, i));
  15. if(H > && board[H-][i] == 'O') que.push(Point(H-, i)); //遇到O,只push,不再调用BFS
  16. }
  17. for(i = ; i < H; ++i){
  18. if(board[i][] == 'O') que.push(Point(i, ));
  19. if(W > && board[i][W-] == 'O') que.push(Point(i, W-)); //遇到O,只push,不再调用BFS
  20. }
  21. while(!que.empty()){ //调用BFS
  22. Point cur = que.front();
  23. que.pop();
  24. board[cur.v][cur.h] = 'Y';
  25. for(int i = ; i < ; i++){
  26. if((cur.v+addV[i]) < H
  27. && (cur.h+addH[i]) < W
  28. && (cur.v+addV[i]) >=
  29. && (cur.h+addH[i]) >=
  30. && board[cur.v+addV[i]][cur.h+addH[i]] == 'O'){
  31. que.push(Point(cur.v+addV[i], cur.h+addH[i]));
  32. }
  33. }
  34. }
  35.  
  36. for(i = ; i < H; ++i){
  37. for(j = ; j < W; ++j){
  38. if(board[i][j] == 'O') board[i][j] = 'X';
  39. if(board[i][j] == 'Y') board[i][j] = 'O';
  40. }
  41. }
  42. }
  43. private:
  44. int addV[] = {, , -, };
  45. int addH[] = {, , , -};
  46. };

小结:

这种需要更改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?

  1. class Solution {
  2. public:
  3. void setZeroes(vector<vector<int> > &matrix) {
  4.  
  5. }
  6. };

这道题的困难之处在于“需要空间复杂度为常量”

有了上一题的启发,我们可以将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,需要额外记录。

代码:

  1. class Solution {
  2. public:
  3. void setZeroes(vector<vector<int> > &matrix) {
  4. if(matrix.size() == ) return;
  5. if(matrix[].size() == ) return;
  6.  
  7. bool firstRowSet = false;
  8. bool firstColSet = false;
  9. int i, j;
  10. for(i = ; i < matrix.size(); ++i){
  11. for(j = ; j < matrix[i].size(); ++j){
  12. if(matrix[i][j] == ){
  13. if(i == ) firstRowSet = true;
  14. if(j == ) firstColSet = true;
  15. matrix[i][] = ;
  16. matrix[][j] = ;
  17. }
  18. }
  19. }
  20.  
  21. for(i = ; i < matrix.size(); ++i){
  22. if(matrix[i][] == ){
  23. for(j = ; j < matrix[i].size(); ++j)
  24. matrix[i][j] = ;
  25. }
  26. }
  27.  
  28. for(j = ; j < matrix[].size(); ++j){
  29. if(matrix[][j] == ){
  30. for(i = ; i < matrix.size(); ++i)
  31. matrix[i][j] = ;
  32. }
  33. }
  34.  
  35. if(firstRowSet)
  36. for(j = ; j < matrix[].size(); ++j)
  37. matrix[][j] = ;
  38. if(firstColSet)
  39. for(i = ; i < matrix.size(); ++i)
  40. matrix[i][] = ;
  41. }
  42. };

[LeetCode] Matrix 值修改系列,例题 Surrounded Regions,Set Matrix Zeroes的更多相关文章

  1. [LeetCode] Surrounded Regions 包围区域

    Given a 2D board containing 'X' and 'O', capture all regions surrounded by 'X'. A region is captured ...

  2. 验证LeetCode Surrounded Regions 包围区域的DFS方法

    在LeetCode中的Surrounded Regions 包围区域这道题中,我们发现用DFS方法中的最后一个条件必须是j > 1,如下面的红色字体所示,如果写成j > 0的话无法通过OJ ...

  3. 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 用了第一种方式, ...

  4. 【LeetCode】130. Surrounded Regions (2 solutions)

    Surrounded Regions Given a 2D board containing 'X' and 'O', capture all regions surrounded by 'X'. A ...

  5. Leetcode之深度优先搜索(DFS)专题-130. 被围绕的区域(Surrounded Regions)

    Leetcode之深度优先搜索(DFS)专题-130. 被围绕的区域(Surrounded Regions) 深度优先搜索的解题详细介绍,点击 给定一个二维的矩阵,包含 'X' 和 'O'(字母 O) ...

  6. [LeetCode] 130. Surrounded Regions 包围区域

    Given a 2D board containing 'X' and 'O'(the letter O), capture all regions surrounded by 'X'. A regi ...

  7. 【leetcode】Surrounded Regions

    Surrounded Regions Given a 2D board containing 'X' and 'O', capture all regions surrounded by 'X'. A ...

  8. LeetCode: Surrounded Regions 解题报告

    Surrounded Regions Given a 2D board containing 'X' and 'O', capture all regions surrounded by 'X'. A ...

  9. 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 ...

随机推荐

  1. Python常用模块之hashlib

    Python里面的hashlib模块提供了很多加密的算法,这里介绍一下hashlib的简单使用事例,用hashlib的md5算法加密数据 import hashlib hash = hashlib.m ...

  2. unrecognized selector send to instancd 快速定位

    1.在Debug菜单中Breakpoints->Create Symbolic Breakpoint; 2.在Symbolic中填写方法签名: -[NSObject(NSObject) does ...

  3. C#的lock语句

    文章:lock 语句(C# 参考) 代码: using System; using System.Threading.Tasks; public class Account { private rea ...

  4. Python学习笔记(二)--变量和数据类型

    python中的数据类型 python中什么是变量 python中定义字符串 raw字符串与Unicode字符串 python中的整数和浮点数 python中的bool类型 --- python中的数 ...

  5. 【leetcode】300.Longest Increasing Subsequence

    Given an unsorted array of integers, find the length of longest increasing subsequence. For example, ...

  6. Java实现的词频统计——Web迁移

    本次将原本控制台工程迁移到了web工程上,依旧保留原本控制台的版本. 需求: 1.把程序迁移到web平台,通过用户上传TXT的方式接收文件: 2.在页面上给出链接 (如果有封皮.作者.字数.页数等信息 ...

  7. 使用ASP.NET Identity 实现WebAPI接口的Oauth身份验证

    使用ASP.NET Identity 实现WebAPI接口的Oauth身份验证   目前WEB 前后端分离的开发模式比较流行,之前做过的几个小项目也都是前后分离的模式,后端使用asp.net weba ...

  8. java 数据结构与算法 之查找法

    一.二分查找法 二分查找就是将查找的键和子数组的中间键作比较,如果被查找的键小于中间键,就在左子数组继续查找:如果大于中间键,就在右子数组中查找,否则中间键就是要找的元素. @Test public ...

  9. webgl学习笔记五-纹理

    写在前面 建议先阅读下前面我的三篇文章. webgl学习笔记一-绘图单点 webgl学习笔记二-绘图多点 webgl学习笔记三-平移旋转缩放 术语 : 纹理 :图像 图形装配区域 :顶点着色器顶点坐标 ...

  10. SQL 抛出异常的例子 RAISERROR 的使用

    先创建一个procedure 当输入的值不在0-100之间时会报出异常 create proc proc_x @a int as begin ) ,) else select @a end go 测试 ...