刷题的一天——深度优先搜索与广度优先搜索

1、有一幅以 m x n 的二维整数数组表示的图画 image ,其中 image[i][j] 表示该图画的像素值大小。你也被给予三个整数 sr , sc 和 newColor 。你应该从像素 image[sr][sc] 开始对图像进行 上色填充 。为了完成 上色工作 ,从初始像素开始,记录初始坐标的 上下左右四个方向上 像素值与初始坐标相同的相连像素点,接着再记录这四个方向上符合条件的像素点与他们对应 四个方向上 像素值与初始坐标相同的相连像素点,……,重复该过程。将所有有记录的像素点的颜色值改为 newColor 。最后返回 经过上色渲染后的图像 。

示例:

输入: image = [[1,1,1],[1,1,0],[1,0,1]],sr = 1, sc = 1, newColor = 2
输出: [[2,2,2],[2,2,0],[2,0,1]]

这个题即图像题可以使用深度优先搜索与广度优先搜索解决。但由于是第一次接触这种算法,所以看了下解答然后照着打了出来

(1)广度优先搜索(BFS):就很奇怪自己打的代码超出时间限制,修改多次也没办法,所以就用了答案的代码。

代码:

class Solution {
public:
    const int dx[4] = {1, 0, 0, -1};    //定义左右方位————x
    const int dy[4] = {0, 1, -1, 0};    //定义上下方位————y
    vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int newColor) {
        int currColor = image[sr][sc];
        if (currColor == newColor) return image;                                  //满足要求则结束循环
        int n = image.size(), m = image[0].size();                                //得出image的长宽
        queue<pair<int, int>> que;                                                 //设置数组对
        que.emplace(sr, sc);                                                        
        image[sr][sc] = newColor;
        while (!que.empty()) {                                                 //保证还有符合要求数组时继续上色
            int x = que.front().first, y = que.front().second;               //带入现有x坐标,在此基础上继续遍历
            que.pop();                                                       //完成上色的最后一步,有que队列清空,结束循环
            for (int i = 0; i < 4; i++) {                                       //广度优先遍历
                int mx = x + dx[i], my = y + dy[i];
                if (mx >= 0 && mx < n && my >= 0 && my < m && image[mx][my] == currColor) {   
                    que.emplace(mx, my);                                    //队列中加入坐标
                    image[mx][my] = newColor;                              //颜色替换
                }
            }
        }
        return image;
    }
};

这一步由于使用的BFS,所以时间复杂度O(mn)(mn是image的长和宽);空间复杂度为O(mn)。

(2)深度优先搜索(DFS)

class Solution {
public:
    const int dx[4] = {-1,0,0,1};                                                 //坐标左右移动
    const int dy[4] = {0,-1,1,0};                                                 //坐标上下移动
    void dfs (vector<vector<int>>& image, int x, int y,int color, int newColor){    //设定dfs函数
        if (image[x][y]==color){                                                    //如果初始坐标不等于newcolor就继续,不然就不掺和了
            image[x][y]=newColor;                                                      //初始坐标等于newcolor   
            for(int i = 0;i<4;i++){                                                    //上下左右方位移动,和bfs思路一样,但是后面略有不同
                int mx = x + dx[i] , my = y +dy[i];                                     
                if (mx>=0 && mx< image.size() && my >= 0 && my< image[0].size() && image[mx][my]==color){
                    dfs (image,mx,my,color,newColor);                                    //最妙的是这一步,充分的利用了迭代,没有就返回上一步。
                }
            }
        }
       
    }

    vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int newColor) {
    int color = image[sr][sc];
    if (image[sr][sc] != newColor){
        dfs(image,sr,sc,color,newColor);                                  //这里就可以用上dfs函数了
    }
    return image; 
    }
};

这一步设定dfs加上再dfs中利用迭代真的是相当漂亮,学到了。

同样的时间复杂度为O(mn),空间复杂度O(mn)。

2、给你一个大小为 m x n 的二进制矩阵 grid 。岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。岛屿的面积是岛上值为 1 的单元格的数目。计算并返回 grid 中最大的岛屿面积。如果没有岛屿,则返回面积为 0 。

示例:

输入:grid = [[0,0,1,0,0,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,1,1,0,1,0,0,0,0,0,0,0,0],[0,1,0,0,1,1,0,0,1,0,1,0,0],[0,1,0,0,1,1,0,0,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,0,0,0,0,1,1,0,0,0,0]]
输出:6

(1)深度优先搜索(DFS)

代码:

class Solution {
    int dfs(vector<vector<int>>& grid, int cur_i, int cur_j) {
        if (cur_i < 0 || cur_j < 0 || cur_i == grid.size() || cur_j == grid[0].size() || grid[cur_i][cur_j] != 1) {  //排除不符合情况结果,不符合即返回0
            return 0;
        }
        grid[cur_i][cur_j] = 0;                                            //岛屿部分置0,防止重复计算
        int di[4] = {0, 0, 1, -1};
        int dj[4] = {1, -1, 0, 0};
        int ans = 1;
        for (int index = 0; index != 4; ++index) {
            int next_i = cur_i + di[index], next_j = cur_j + dj[index];
            ans += dfs(grid, next_i, next_j);                                  //经典dfs算法,定义dfs函数计算岛屿面积ans
        }
        return ans;
    }
public:
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        int ans = 0;
        for (int i = 0; i != grid.size(); ++i) {                                     //一个一个遍历表格
            for (int j = 0; j != grid[0].size(); ++j) {
                ans = max(ans, dfs(grid, i, j));                                      //得到最大岛屿数
            }
        }
        return ans;
    }
};

时间复杂度O(mn),遍历所有表格所得;空间复杂度O(mn),递归真个网络的大小。

(2)深度优先搜索(DFS)+栈

class Solution {
public:
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        int ans = 0;
        for (int i = 0; i != grid.size(); ++i) {                                //遍历矩阵
            for (int j = 0; j != grid[0].size(); ++j) { 
                int cur = 0;                                                   //cur每次清零计算下一个岛屿的面积
                stack<int> stacki;                                              //i,j坐标推入栈
                stack<int> stackj;
                stacki.push(i);
                stackj.push(j);
                while (!stacki.empty()) {                                         //如果栈不为空则继续计算
                    int cur_i = stacki.top(), cur_j = stackj.top();              //得到栈顶的坐标
                    stacki.pop();                                                //返回栈顶的值,然后删除顶上的值
                    stackj.pop();
                    if (cur_i < 0 || cur_j < 0 || cur_i == grid.size() || cur_j == grid[0].size() || grid[cur_i][cur_j] != 1) {
                        continue;                                                   //如果满足这个要求就打断接下来的操作(没必要继续了)
                    }
                    ++cur;                                                             //目前的岛屿面积+1,之后把该坐标清零
                    grid[cur_i][cur_j] = 0;
                    int di[4] = {0, 0, 1, -1};
                    int dj[4] = {1, -1, 0, 0};
                    for (int index = 0; index != 4; ++index) {                             //深度优先搜索
                        int next_i = cur_i + di[index], next_j = cur_j + dj[index];
                        stacki.push(next_i);
                        stackj.push(next_j);
                    }
                }
                ans = max(ans, cur);
            }
        }
        return ans;
    }
};

这一块的思想不错,但是代码并没有那么简洁。不是太推荐。时间复杂度O(mn),空间复杂度O(mn),基本都差不多,而且写代码比之前费时。

(3)广度优先搜素(BFS)

class Solution {
public:
    int maxAreaOfIsland(vector<vector<int>>& grid) {
    int ans = 0;
     for (int i = 0;i < grid.size();++i){
        for( int j = 0 ;j < grid[0].size() ; ++j){
            int cur = 0;
            queue<int>quei;
            queue<int>quej;
            quei.push(i);
            quej.push(j);
            while(! quei.empty()){
               int iso_x = quei.front(),iso_y = quej.front();
               quei.pop();
               quej.pop();
               if(iso_x<0 || iso_x ==grid.size() ||iso_y<0 || iso_y ==grid[0].size() || grid[iso_x][iso_y]!=1){
                   continue;
               }
               cur ++;
               grid[iso_x][iso_y]=0;
               int dx[4] = {-1,0,0,1},dy[4] = {0,-1,1,0};
               for (int a = 0;a !=4 ; ++a){
                 int next_x = iso_x +dx[a],next_y = iso_y +dy[a];
                 quei.push(next_x);
                 quej.push(next_y);
               }
            }
            ans = max (ans,cur);
        }
     }
     return ans;
    }
};

大概思想就是(2)中的深度优先搜索DFS那一套,但是用的是队列而不是栈,先进先出符合广度优先搜索的特点。而且发现自己的一些条件设定有点问题,这里面的条件设定可以很好的减少时间消耗,值得学习。时间复杂度O(mn),空间复杂度O(mn)。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值