floodfill算法(1)

一:图像渲染

题目:

有一幅以m*n的二维数组表示的图画image,其中image[i][j]表示该图像的像素值大小

给出三个整数sr,sc,和color,从像素image[i][j]开始对图像进行上色填充,为了完成上色工作,从初始像素开始,记录初始坐标的上下左右四个方向上相邻且同色的像素点,接着再记录与这些像素点相邻且同色的新像素点......重复此过程,将所有有记录的像素点的颜色改为color,最后返回经过上色渲染后的图像。

方法:

1:画出决策树(同之前的题目基本一致,故省略)

2:算法原理

基本思路:分为两种情况,如果image[sr][sc]等于color,可以直接返回image,如果不相等,从当前位置开始,利用dx[4],和dy[4]两个数组,对其上下左右四个位置是否需要渲染进行判断,符合条件对其进行递归

dfs函数:

void dfs(iamge, i, j, color)(数组,当前位置,需要渲染改变的值)

不需要设置递归出口,直接在image数组上对其进行操作即可

class Solution {
    int m,n;//矩阵的行和列
    int path;//记录的需要更改的值
    //上下左右四个位置
    int dx[4] = {0,0,1,-1};
    int dy[4] = {1,-1,0,0};
    
public:
    vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int color) {
        if(image[sr][sc]==color)  return image;//如果数据相同,可以直接返回
        m = image.size(),n = image[0].size();
        path = image[sr][sc];//用一个全局变量直接存放需要进行比较的值
        image[sr][sc] = color;
        dfs(image,sr,sc,color);//把坐标和数组传过去
        return image;
    }

    void dfs(vector<vector<int>>& image,int i,int j,int color)
    {
        //无需递归出口,直接在循环里进行遍历即可
        for(int k = 0;k<4;k++)
        {
            int x = i + dx[k],y = j + dy[k];
            if(x>=0&&x<m&&y>=0&&y<n&&image[x][y]==path)//注意不要过界
            {
                image[x][y] = color;
                dfs(image,x,y,color);
            }

        }
    }
};

二:岛屿数量

题目:

给一个由‘1’(陆地)和‘0’(水)组成的二维网络,请计算网格中岛屿的数量

介绍:岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成,可以假设该网络的四条边均被水包围

方法:

1:画出决策树(与之前的题目基本一致,故省略)

2:算法原理

基本思路:先进行一次遍历,找到为‘1’的位置,然后进入到递归中,将其周围的为‘1’的位置全部变为‘0’,递归回来后再将岛屿的数量加上1

dfs函数:

void dfs(grid,i,j)(grid为给出的数组,(i,j)为当前为‘1’的位置)

class Solution {
    //直接改变原本的数值
    int ret;//总共的岛屿数量
    int m,n;
    int dx[4] = {0,0,1,-1};
    int dy[4] = {1,-1,0,0};

public:
    int numIslands(vector<vector<char>>& grid) {
    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] == '1')
            {
                dfs(grid,i,j);//将周围的的‘1’都变为‘0’
                ret+=1;
            }
        }
    } 
    return ret;  
    }

    void dfs(vector<vector<char>>& grid,int i,int j)
    {
        for(int k = 0;k<4;k++)
        {
            int x = i + dx[k],y = j + dy[k];
            if(x>=0&&x<m&&y>=0&&y<n&&grid[x][y]=='1')
            {
                grid[x][y] = '0';
                dfs(grid,x,y);
            }
        }
    }
};

三:岛屿的最大面积

题目:

给一个大小为m*n的二进制矩阵岛屿grid

岛屿是由一些相邻的1(代表土地)构成的组合,这里的相邻要求两个1必须在水平或者竖直的四个方向上相邻,可以假设grid的四个边缘都被0(代表水)包围着

岛屿的面积是岛上值为1的单元格的数目

方法:

1:画出决策树(与之前题目基本一致,故省略)

2:算法原理

基本思路:先将数组进行遍历,若遇到1,则将其位置直接传入到dfs中,计算此块儿岛屿的面积,然后将其最后存放最大面积的ret进行比较,存放值。在dfs函数中,从传入的位置开始,上下左右四个位置进行判断,更改,然后每进行一次dfs,用来计数面积的count就加1.

class Solution {
    int m,n;
    int ret;//岛屿的最大面积
    int dx[4] = {0,0,1,-1};
    int dy[4] = {1,-1,0,0};
    int count;
public:
    int maxAreaOfIsland(vector<vector<int>>& grid) {
    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] == 1)
            {
                count = 0;
                grid[i][j] = 0;
                dfs(grid,i,j);
                ret = max(ret,count);
            }
        }
    }
    return ret;
    }

    void dfs(vector<vector<int>>& grid,int i,int j)
    {
        count++;
        for(int k = 0;k<4;k++)
        {
            int x = i + dx[k],y = j + dy[k];
            if(x>=0&&x<m&&y>=0&&y<n&&grid[x][y]==1)
            {
                 grid[x][y] = 0;//计数之后将这处的值改为0
                 dfs(grid,x,y);
            }
        }
    }
};

四:被围绕的区域

题目:

给一个m*n的矩阵board,由若干字符‘X’和‘0’组成,捕获所有被围绕的区域:

(1)连接:一个单元格与水平或垂直方向上相邻的单元格

(2)区域:连接所有‘0’的单元格来形成一个区域

(3)如果您可以用‘X’单元格连接这个区域,并且区域中没有任何单元格位于board边缘,则该区域被‘X’单元格围绕

通过将输入矩阵board中的所有‘0’替换为‘X’来捕获被围绕的区域

方法:

1:画出决策树(与之前题目基本一致,故在此省略)

2:算法原理

基本思路:

解法一:直接进行深度优先遍历(过于复杂,不考虑)

解法二:正难则反(重要方法!!!)

首先把边界处理一下,边界为0的对其上下左右进行比遍历,若遇到值为0的位置,将其进行标记

(可以使用vis数组,或者将值进行改变,后续再进行复原)

class Solution {
    int dy[4] = {0,0,1,-1};
    int dx[4] = {1,-1,0,0};
    int m,n;
    
public:
    void solve(vector<vector<char>>& board) {
    m = board.size(),n = board[0].size();
    //将与边界相连的o修改为.
    for(int j = 0;j<n;j++)
    {
        if(board[0][j] == 'O')  dfs(board,0,j);
        if(board[m-1][j] == 'O') dfs(board,m-1,j);
    }
    for(int i = 0;i<m;i++)
    {
        if(board[i][0] == 'O')  dfs(board,i,0);
        if(board[i][n-1] == 'O')  dfs(board,i ,n-1);
    }

    //复原
    for(int i = 0;i<m;i++)
    {
        for(int j = 0;j<n;j++)
        {
            if(board[i][j] == '.') board[i][j] = 'O';
            else if(board[i][j] == 'O')  board[i][j] = 'X';
        }
    }
    }

    void dfs(vector<vector<char>>& board,int i,int j)
    {
        board[i][j] = '.';
        for(int k = 0;k<4;k++)
        {
            int x = i+dx[k],y = j+dy[k];
            if(x>=0&&x<m&&y>=0&&y<n&&board[x][y] == 'O')
            {
                dfs(board,x,y);
            }
        }
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值