最大海岛面积问题的不同解法
问题举例
给定一个包含了一些 0 和 1 的非空二维数组 matrix 。
一个岛屿是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在水平或者竖直方向上相邻。你可以假设matrix的四个边缘都被 0(代表水)包围着。
找到给定的二维数组中最大的岛屿面积。(如果没有岛屿,则返回面积为 0 。)
示例 1:
[[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。注意答案不应该是 11 ,因为岛屿只能包含水平或垂直的四个方向的 1 。
解题思路
上面的示例中,任意相邻的1构成一个海岛,则最大海岛面积,就是成片的1里面1的最大数量。这个是典型的图面问题,可以用深度优先搜索、基于栈的深度优先搜索、广度优先搜等思路来求解。
深度优先搜索:
1. 初始化岛屿面积为0;
2. 如果某个位置数值越界、数值为0或者已经搜索过,跳过;
3. 如果某个点数值为1,且未搜索过,岛屿面积加1,该位置标记为已搜索,然后往上下左右四个方向搜索(执行过程2~3);
4. 搜索结束后,返回当前搜索岛屿的面积
5. 遍历矩阵的各个位置,计算岛屿面积最大值;
6. 输出最大值;
深度优先搜索方法能快速求出岛屿最大面积,但矩阵规模较大时,因为深度搜索层数较多,可能存在栈溢出问题,因此产生了基于栈的深度优先搜索方法。
基于栈的深度优先搜索:
1. 初始化岛屿面积为0,初始化栈(记录数值为1的位置);
2. 如果某个位置数值越界、数值为0或者已经搜索过,跳过;
3. 如果某个点数值为1,且未搜索过,岛屿面积加1,该位置标记为已搜索,该位置压入栈中;
4. 记录栈顶位置,栈顶元素出栈,然后栈顶元素往上下左右四个方向搜索(执行过程2~3);
5. 栈为空时,搜索结束,返回当前搜索岛屿的面积
6. 遍历矩阵的各个位置,计算岛屿面积最大值;
7. 输出最大值;
该方法用栈对已搜索过的位置进行了存储,避免了搜索层数过多问题,能有效避免栈溢出。
广度优先搜索:
1. 初始化岛屿面积为0,初始化队列(记录数值为1的位置);
2. 如果某个位置数值越界、数值为0或者已经搜索过,跳过;
3. 如果某个点数值为1,且未搜索过,岛屿面积加1,该位置标记为已搜索,该位置压入队列中;
4. 记录队首位置,队首元素弹出,然后往上下左右四个方向搜索(执行过程2~3);
5. 队列为空时,搜索结束,返回当前搜索岛屿的面积
6. 遍历矩阵的各个位置,计算岛屿面积最大值;
7. 输出最大值;
广度优先搜索和基于栈的深度优先搜索方法原理接近,但用不同的数据结构来存储搜索过的位置,因此弹出元素不一样,后续搜索位置也不一样。
代码实现
基于栈的深度优先搜索
class DfsClass
{
public:
std::vector<std::vector<int>> Matrix;
std::vector<int> Dir = { -1,0,1,0,-1 };
int GetMaxValue()
{
int maxValue = 0;
for (int i = 0; i < Matrix.size(); ++i)
{
for (int j = 0; j < Matrix[i].size(); ++j)
{
if (Matrix[i][j] == 0) continue;
int tempValue = Matrix[i][j];
Matrix[i][j] = 0;
std::stack<std::pair<int, int>> tempStack;
tempStack.push(std::make_pair(i, j));
while (!tempStack.empty())
{
std::pair<int, int> top = tempStack.top();
tempStack.pop();
for (int k = 0; k < 4; ++k)
{
int x = top.first + Dir[k];
int y = top.second + Dir[k+1];
if (x >= 0 && x < Matrix.size() && y >= 0 && y < Matrix[x].size() && Matrix[x][y]>0)
{
tempValue = tempValue + Matrix[x][y];
Matrix[x][y] = 0;
tempStack.push(std::make_pair(x, y));
}
}
}
maxValue = std::max(maxValue, tempValue);
}
}
return maxValue;
}
};
int GetMaxValue(std::vector<std::vector<int>> matrix)
{
DfsClass* dnfClass = new DfsClass();
dnfClass->Matrix = matrix;
return dnfClass->GetMaxValue();
}
int main()
{
std::vector<std::vector<int>> matrix =
{
{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}
};
int maxValue = GetMaxValue(matrix);
std::cout << maxValue;
}
其他的深度优先和广度优先代码类似,不再提供。
结果
最大岛屿标记位置如图示(倾斜加粗位置):
{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。
代码运行结果如下图:
因此,代码运行结果符合预期。