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)。