题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
题目描述:给你一个 m x n 的矩阵 board ,由若干字符 'X' 和 'O' ,找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。
解题思路(思路一是自己的思路,思路二题解思路,不过用两种遍历方式写出来)
思路一(深度优先遍历):
我的思路:是开辟一个二维数组,存储二元组,来记录那些下标,首先是一个一维数组,每次记录我们当前遍历岛屿的下标,当被环绕的时候压入到二维数组中,否则直接清空。类似将所有岛屿都淹没,然后再看哪些岛屿没被包围再还原成陆地。
- class Solution {
- public:
- bool flag = true; //表示是否被环绕(只要相连的岛屿有一个在边界就不是被环绕的),被环绕就不用撤回修改
- vector<vector<pair<int,int>>> vec;//存所有岛屿下标,其中全都是要变回'O'的
- vector<pair<int,int>> tmp; //保存当前遍历这片岛屿的下标,一会可能填充。
- void dfs(vector<vector<char>> &grid,int x,int y){
- if(x < 0 || y < 0 || x >= grid.size() || y >= grid[0].size()){
- flag = false;//表示没有被环绕
- return ;
- }
- if(grid[x][y] == 'X') return;
- tmp.push_back({x,y});//压入当前岛屿的下标
- grid[x][y] = 'X';
- dfs(grid,x+1,y);
- dfs(grid,x-1,y);
- dfs(grid,x,y+1);
- dfs(grid,x,y-1);
- }
- void solve(vector<vector<char>>& grid) {
- int m = grid.size(),n = grid[0].size();
- for(int i=0;i<m;i++){
- for(int j=0;j<n;j++){
- if(grid[i][j] == 'O'){
- dfs(grid,i,j);
- //当flag为false,也就是岛屿没有被包围,我们就将其压入vec中,最后再还原
- if(flag == false){
- vec.push_back(tmp);
- tmp.clear();//这里注意要把tmp清空了,方便下次使用
- flag = true;//flag再改为默认值
- }else{
- //这里不改flag是因为如果走这个分支,那flag一定还是默认值true
- tmp.clear();
- }
- }
- }
- }
- //将未被包围的小岛屿还原为'O'
- for(int i=0;i<vec.size();i++){
- for(int j=0;j<vec[i].size();j++){
- grid[vec[i][j].first][vec[i][j].second] = 'O';
- }
- }
- return ;
- }
- };
思路二(广度优先遍历):
比较猛的一个思路:本题我们可以看到,只有和边界相连的O不会变,其余的都得变成X,那么我们可以将与边界相连的所有O全部变成一个特定符号如'-',这样,其中所有的'-'都是与边界相连的,马上会再变成'O'。而这个时候图中所有的'O'都是被包围的,全都变为'X'即可。
- class Solution {
- public:
- int dir[4][2] = {0,1,1,0,-1,0,0,-1};
- void bfs(vector<vector<char>> &grid,int x,int y){
- queue<pair<int,int>> que;
- que.push({x,y});
- grid[x][y] = '-';//将与边界相连的全部变为'-'
- //广度优先遍历
- while(!que.empty()){
- pair<int,int> cur = que.front();
- que.pop();
- for(int i=0;i<4;i++){
- int nextx = cur.first + dir[i][0];
- int nexty = cur.second + dir[i][1];
- if(nextx < 0 || nexty < 0 || nextx >= grid.size() || nexty >= grid[0].size() ||grid[nextx][nexty] != 'O') continue;
- que.push({nextx,nexty});
- grid[nextx][nexty] = '-';
- }
-
- }
- }
- void solve(vector<vector<char>>& grid) {
- int row = grid.size(),col = grid[0].size();
- for(int i=0;i<col;i++){
- //遍历第一行的所有列
- if(grid[0][i] == 'O') bfs(grid,0,i);
- //遍历最后一行的所有列
- if(grid[row-1][i] == 'O') bfs(grid,row-1,i);
- }
- for(int i=0;i<row;i++){
- //遍历第一列的所有行
- if(grid[i][0] == 'O') bfs(grid,i,0);
- //遍历最后一列的所有行
- if(grid[i][col-1] == 'O') bfs(grid,i,col-1);
- }
- //这个时候图中所有'-'都是与边界相连的,所有'O'都是被包围起来的。
- for(int i=0;i<row;i++){
- for(int j=0;j<col;j++){
- //这俩式子顺序反了,导致花了我半小时调试
- if(grid[i][j] == 'O')grid[i][j] = 'X';
- if(grid[i][j] == '-')grid[i][j] = 'O';
- }
- }
- return ;
- }
- };
总结:
题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
题目描述:有一个 m × n 的矩形岛屿,与 太平洋 和 大西洋 相邻。 “太平洋” 处于大陆的左边界和上边界,而 “大西洋” 处于大陆的右边界和下边界。
这个岛被分割成一个由若干方形单元格组成的网格。给定一个 m x n 的整数矩阵 heights , heights[r][c] 表示坐标 (r, c) 上单元格 高于海平面的高度 。
岛上雨水较多,如果相邻单元格的高度 小于或等于 当前单元格的高度,雨水可以直接向北、南、东、西流向相邻单元格。水可以从海洋附近的任何单元格流入海洋。
返回网格坐标 result 的 2D 列表 ,其中 result[i] = [ri, ci] 表示雨水从单元格 (ri, ci) 流动 既可流向太平洋也可流向大西洋 。
解题思路
首先明确本题题意,意思就是雨水高的地方能往雨水低的地方流,要我们求出能流向两大洋的点坐标。
思路一(深度优先遍历):
这题总体思路就是遍历边界点(也就是能直接流进大洋的点),再逆流遍历,因为雨水往低处流,我们逆流遍历就可以找到所有大于边界的雨水高度的点,这些点就是可以直接流进大洋的点
- class Solution {
- private:
- int dir[4][2] = {-1, 0, 0, -1, 1, 0, 0, 1}; // 保存四个方向
-
- // 从低向高遍历,注意这里visited是引用,即可以改变传入的pacific和atlantic的值
- void dfs(vector<vector<int>>& heights, vector
>& visited, int x, int y) { - if (visited[x][y]) return;
- visited[x][y] = true;
- for (int i = 0; i < 4; i++) { // 向四个方向遍历
- int nextx = x + dir[i][0];
- int nexty = y + dir[i][1];
- // 超过边界
- if (nextx < 0 || nextx >= heights.size() || nexty < 0 || nexty >= heights[0].size()) continue;
- // 高度不合适,注意这里是从低向高判断
- if (heights[x][y] > heights[nextx][nexty]) continue;
-
- dfs (heights, visited, nextx, nexty);
- }
- return;
- }
- public:
-
- vector<vector<int>> pacificAtlantic(vector
>& heights) { - vector<vector<int>> result;
- int n = heights.size();
- int m = heights[0].size(); // 这里不用担心空指针,题目要求说了长宽都大于1
-
- // 记录从太平洋边出发,可以遍历的节点
- vector<vector<bool>> pacific = vector
>(n, vector(m, false)); - // 记录从大西洋出发,可以遍历的节点
- vector<vector<bool>> atlantic = vector
>(n, vector(m, false)); - // 从最上最下行的节点出发,向高处遍历
- for (int i = 0; i < n; i++) {
- dfs (heights, pacific, i, 0); // 遍历最上行,接触太平洋
- dfs (heights, atlantic, i, m - 1); // 遍历最下行,接触大西洋
- }
-
- // 从最左最右列的节点出发,向高处遍历
- for (int j = 0; j < m; j++) {
- dfs (heights, pacific, 0, j); // 遍历最左列,接触太平洋
- dfs (heights, atlantic, n - 1, j); // 遍历最右列,接触大西洋
- }
- for (int i = 0; i < n; i++) {
- for (int j = 0; j < m; j++) {
- // 如果这个节点,从太平洋和大西洋出发都遍历过,就是结果
- if (pacific[i][j] && atlantic[i][j]) result.push_back({i, j});
- }
- }
- return result;
- }
- };
总结: