刷题日志【3】

发布于:2024-12-18 ⋅ 阅读:(48) ⋅ 点赞:(0)

目录

1、图像渲染

2、被围绕的区域


1、图像渲染

题意简单说就是病毒扩散,感染数字相同且临近的数字

 作者了解后发现,在类题目为floodfill算法,主要情况为将属性相同的同一个矩阵的一个范围内的元素进行操作

这个题目,作者的解法和刷题【2】里面的【黄金矿工】一样,迷宫找路,不过不用return后还原现场,作者最后返回的就是题目给的变量,只管深搜,不管恢复 

class Solution {
    //target是所有要感染的数字的值,扩散只能感染值为target的数
    //color是要染成的新的值

int target;
int color;
//m是row,n是col
int m,n;
//dx,dy为方向向量

int dx[4]={0,0,-1,1};
int dy[4]={1,-1,0,0};
//防止走回头路
bool check[51][51];





public:
    vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int _color) {
        m=image.size();
        n=image[0].size();

        target=image[sr][sc];
color=_color;
//有可能根本不用改,不要浪费时间,直接return

if(target==color)
{

    return image;
}
image[sr][sc]=color;
check[sr][sc]=true;

dfs(image,sr,sc);


return image;


    }

void dfs(vector<vector<int>>& image, int i,int j)
{


for(int p=0;p<4;p++)
{
int x=i+dx[p];
int y=j+dy[p];

if(x>=0&&x<m&&y>=0&&y<n&&!check[x][y]&&image[x][y]==target)
{
image[x][y]=color;
check[x][y]=true;
dfs(image,x,y);
//没有还原现场

}

}

}






};

2、被围绕的区域

这个题比之前无脑dfs难一点,就是怎么处理这个边界问题,作者最初想着dfs统一对’O‘进行替换,在dfs内部用一个if做剪枝,一旦含有边界的数,就将改动的’O‘还原,然后这个消息用dfs的返回值进行返回(如搞一个bool的返回),但是发现这样会把边界的一块 'O'给拆散(因为return false,就不会再进行其他支路,意味着对联通块的遍历可能会在一遇到边界数就结束遍历,剩下一部分没有用check标记(这个check指的就是前面题目的标记量)) 

 作者去看了一下其他解法:使用两个dfs,dfs1先对沾有边界的连通块进行标记,即dfs1不会对值进行更改,dfs2是处理剩下的’O‘,再次对board遍历,因为边界的块已经标记,不会再次出现,所以dfs2可以进行值的替换

class Solution {
int dx[4]={0,0,-1,1};
int dy[4]={1,-1,0,0};
//防止走回头路
bool check[201][201];
int m,n;


public:
    void solve(vector<vector<char>>& board) {
        m=board.size();
        n=board[0].size();

        for(int i=0;i<m;i++)
        {
for(int j=0;j<n;j++)
{
if((i==0||i==m-1||j==0||j==n-1)&&board[i][j]=='O'&&!check[i][j])
{
    check[i][j]=true;
    dfs1(board,i,j);

}


}

        }


for(int i=0;i<m;i++)
{for(int j=0;j<n;j++)
{
if(board[i][j]=='O'&&!check[i][j])
{check[i][j]=true;
board[i][j]='X';
    dfs2(board,i,j);
}

}
    }





        

    }

void dfs1(vector<vector<char>>& board,int i,int j)
{
    
for(int p=0;p<4;p++)
{
int x=i+dx[p];
int y=j+dy[p];
if(x>=0&&x<m&&y>=0&&y<n&&!check[x][y]&&board[x][y]=='O')
{
check[x][y]=true;
dfs1(board,x,y);

}


}


}



void dfs2(vector<vector<char>>& board,int i,int j)
{
for(int p=0;p<4;p++)
{
int x=i+dx[p];
int y=j+dy[p];
if(x>=0&&x<m&&y>=0&&y<n&&!check[x][y]&&board[x][y]=='O')
{
check[x][y]=true;
board[x][y]='X';
dfs2(board,x,y);

}


}


}





};class Solution {
int dx[4]={0,0,-1,1};
int dy[4]={1,-1,0,0};
//防止走回头路
bool check[201][201];
int m,n;


public:
    void solve(vector<vector<char>>& board) {
        m=board.size();
        n=board[0].size();

        for(int i=0;i<m;i++)
        {
for(int j=0;j<n;j++)
{
if((i==0||i==m-1||j==0||j==n-1)&&board[i][j]=='O'&&!check[i][j])
{
    check[i][j]=true;
    dfs1(board,i,j);

}


}

        }


for(int i=0;i<m;i++)
{for(int j=0;j<n;j++)
{
if(board[i][j]=='O'&&!check[i][j])
{check[i][j]=true;
board[i][j]='X';
    dfs2(board,i,j);
}

}
    }





        

    }

void dfs1(vector<vector<char>>& board,int i,int j)
{
    
for(int p=0;p<4;p++)
{
int x=i+dx[p];
int y=j+dy[p];
if(x>=0&&x<m&&y>=0&&y<n&&!check[x][y]&&board[x][y]=='O')
{
check[x][y]=true;
dfs1(board,x,y);

}


}


}



void dfs2(vector<vector<char>>& board,int i,int j)
{
for(int p=0;p<4;p++)
{
int x=i+dx[p];
int y=j+dy[p];
if(x>=0&&x<m&&y>=0&&y<n&&!check[x][y]&&board[x][y]=='O')
{
check[x][y]=true;
board[x][y]='X';
dfs2(board,x,y);

}


}


}





};

3、太平洋大西洋水流问题

题目的意思就是找到坐标,水可以从这里流向两个海洋,(水从高到低,同时,相平的也可以流动)

1、解法一(暴力枚举)

class Solution {


int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
bool check[201][201];
int m,n;

//是否触碰到P的边界,
//是否触碰到A的边界

bool is_P;
bool is_A;





public:
    vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) 
    {
        m=heights.size();
        n=heights[0].size();
        vector<vector<int>> ret;
//对每个点都判断,即将每个点都当做山峰的顶点
//check与之前不一样,之前check遍历记录为true的不会在主函数力在遍历
//而这一题的思路是把check仅仅使用在深度遍历时,保证深度遍历步重复
//但面对新的【i】【j】,check是视为互不干扰的

//
        for(int i=0;i<m;i++)
        {
for(int j=0;j<n;j++)
{

check[i][j]=true;
if(i==0||j==0)
{
    is_P=true;

}
if(i==m-1||j==n-1)
{
is_A=true;
}
dfs(heights,i,j);
//一旦以【i】【j】为顶点的路对应的变量is_p和is_A为true时意为着以该顶点可以触碰到两个海洋
if(is_A&&is_P)
{
ret.push_back({i,j});

}

is_A=is_P=false;
//check对每一个【i】【j】是一次性的
memset(check,0,sizeof(check));


}

        }


return ret;

    }





void dfs(vector<vector<int>>& heights,int i,int j)
{

for(int p=0;p<4;p++)
{
    int x=i+dx[p];
    int y=j+dy[p];

if(x>=0&&x<m&&y>=0&&y<n&&!check[x][y]&&heights[i][j]>=heights[x][y])
{
check[x][y]=true;

if(x==0||y==0)
{
    is_P=true;

}
if(x==m-1||y==n-1)
{
is_A=true;
}
if(is_A&&is_P)
{
    return ;
}
dfs(heights,x,y);

}




}




}



};

2、解法二:逆向思考

题目要找到是扩散到达两个海的节点,反过来思考,两个海能够向上爬,并且相交,就是目标点

class Solution {

bool check_P[201][201];
bool check_A[201][201];

int dx[4]={0,0,-1,1};
int dy[4]={1,-1,0,0};
int m,n;


public:
    vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights)
    {
        
        m=heights.size();
    n=heights[0].size();


    for(int i=0;i<m;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i==0||j==0)
        {
check_P[i][j]=true;
dfs_P(heights,i,j);

        }
        if(i==m-1||j==n-1)
        {

check_A[i][j]=true;
dfs_A(heights,i,j);

        }
        }
    }
        
        vector<vector<int>> ret;

for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{if(check_A[i][j]&&check_P[i][j])
{
ret.push_back({i,j});
}


}

}





return ret;

    }

void dfs_A(vector<vector<int>>& heights,int i,int j)
{
for(int p=0;p<4;p++)
{
    int x=i+dx[p];
    int y=j+dy[p];

if(x>=0&&x<m&&y>=0&&y<n&&!check_A[x][y]&&heights[i][j]<=heights[x][y])
{
    check_A[x][y]=true;
    dfs_A(heights,x,y);

}

}


}

void dfs_P(vector<vector<int>>& heights,int i,int j)
{
for(int p=0;p<4;p++)
{
    int x=i+dx[p];
    int y=j+dy[p];

if(x>=0&&x<m&&y>=0&&y<n&&!check_P[x][y]&&heights[i][j]<=heights[x][y])
{
    check_P[x][y]=true;
    dfs_P(heights,x,y);
    
}

}


}









};