该题的思路可以有很多,我这里因为最近学习了DFS,所以我的第一思路是DFS
下面这个是我写的代码(很冗长(思路不太好))
我的第一思路:遇到1就进入深度搜索这个岛屿,每一块土地我都遍历它的上下左右,如果这些方向的土地上有越界的或者说是水的那么我的计数++(同时标记这块土地)
之后再继续深搜
最后输出这个计数结果即可
class Solution {
public:
int n, m, tx, ty, nextt[4][2] = { {0,1},{1,0},{0,-1},{-1,0} };
int cn = 0;
vector<vector<int> >book;
void dfs(vector<vector<int> >& grid, vector<vector<int> >& book, int n, int m, int x, int y)
{
if (grid[x][y] == 1)
{
book[x][y] = 1;
for (int i = 0; i < 4; i++)
{
tx = x + nextt[i][0];
ty = y + nextt[i][1];
if (tx < 0 || ty < 0 || tx >= n || ty >= m) {
cn++;
book[x][y] = 1;
continue;
}
if (grid[tx][ty] == 0)
cn++;
}
for (int i = 0; i < 4; i++)
{
tx = x + nextt[i][0];
ty = y + nextt[i][1];
if (tx < 0 || ty < 0 || tx >= n || ty >= m || grid[tx][ty] == 0 || book[tx][ty] == 1)
continue;
dfs(grid, book, n, m, tx, ty);
}
}
return;
}
int islandPerimeter(vector<vector<int>>& grid) {
n = grid.size();
m = grid[0].size();
book = vector<vector<int> >(n, vector<int>(m, 0));
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (grid[i][j] == 1&&book[i][j]==0)
{
dfs(grid, book, n, m, i, j);
}
}
}
return cn;
}
};
下面这个代码是DFS做法的官方题解 (思路和我一样,只不过写法不同)
此时遍历的方式可扩展至统计多个岛屿各自的周长。需要注意的是为了防止陆地格子在深度优先搜索中被重复遍历导致死循环,我们需要将遍历过的陆地格子标记为已经遍历过,下面的代码中我们设定值为 2 的格子为已经遍历过的陆地格子
class Solution {
constexpr static int dx[4] = {0, 1, 0, -1};
constexpr static int dy[4] = {1, 0, -1, 0};
public:
int dfs(int x, int y, vector<vector<int>> &grid, int n, int m) {
if (x < 0 || x >= n || y < 0 || y >= m || grid[x][y] == 0) {
return 1;
}
if (grid[x][y] == 2) {
return 0;
}
grid[x][y] = 2;
int res = 0;
for (int i = 0; i < 4; ++i) {
int tx = x + dx[i];
int ty = y + dy[i];
res += dfs(tx, ty, grid, n, m);
}
return res;
}
int islandPerimeter(vector<vector<int>> &grid) {
int n = grid.size(), m = grid[0].size();
int ans = 0;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (grid[i][j] == 1) {
ans += dfs(i, j, grid, n, m);
}
}
}
return ans;
}
};
下面给出BFS的做法(刚学还不是很熟练)
bfs判断条件时机一般有两个,一个是入队时候判断,一个是出队时候判断,为了精简代码,经常在出队时候做判断,这样只要写一处代码,入队判断要写两处,一处是第一个结点入队的时候,第二个是相邻结点入队的时候。为了防止重复计算,必须入队时候果断加入判断标记
class Solution {
public:
int ans = 0, tx, ty, nextt[4][2] = { {0,1},{1,0},{0,-1},{-1,0} }, cn = 0;
int bfs(vector<vector<int>>& grid, int x, int y, int n, int m)
{
queue<pair<int, int> >q;
q.push({ x,y });
grid[x][y] = 2;//入队标记
while (!q.empty())
{
pair<int, int> ij;
ij = q.front();
q.pop();
for (int i = 0; i < 4; i++)
{
tx = ij.first + nextt[i][0];
ty = ij.second + nextt[i][1];
if (tx >= 0 && tx < n && ty >= 0 && ty < m && grid[tx][ty] == 1)
{
grid[tx][ty] = 2;//入队标记
q.push({ tx,ty });
}
if (tx < 0 || ty < 0 || tx >= n || ty >= m || grid[tx][ty] == 0 || grid[tx][ty] == 2)
{
if (tx < 0 || ty < 0 || tx >= n || ty >= m || grid[tx][ty] == 0)
{
cn++;
}
continue;
}
}
}
return cn;
}
int islandPerimeter(vector<vector<int>>& grid) {
int n = grid.size();
int m = grid[0].size();
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (grid[i][j] == 1)
{
ans+=bfs(grid, i, j, n, m);
}
}
}
return ans;
}
};
下面这个思路是我在别人的题解中找到的(非常简单的思路)
我们直接遍历整个数组,如果遇到土地的话,我们就检查这块土地的上面那块是不是土地,以及检查这块土地的左边那块是不是土地,即检查接壤的土地有多少,我们知道土地接壤必然会占用两条边,所以我们最后的答案就是——土地数*4-接壤土地数*2
class Solution {
public:
int ans=0;
int islandPerimeter(vector<vector<int>>& grid) {
if(grid.size()==0)
return 0;
for(int i=0;i<grid.size();i++)
{
for(int j=0;j<grid[0].size();j++)
{
if(grid[i][j]==1)
{
ans+=4;
if(j>0&&grid[i][j-1]==1)
{
ans-=2;
}
if(i>0&&grid[i-1][j]==1)
{
ans-=2;
}
}
}
}
return ans;
}
};
下面这个代码运用了迭代,其实和上面DFS算法的思路一致,只不过没有运用递归,直接遍历数组罢了,这里便不再过多赘述~~~
class Solution {
public://迭代
int islandPerimeter(vector<vector<int>>& grid) {
int n=grid.size();
int m=grid[0].size();
int nextt[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int tx,ty;
int ans=0,cn=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(grid[i][j]==1)
{
cn=0;
for(int z=0;z<4;z++)
{
tx=i+nextt[z][0];
ty=j+nextt[z][1];
if(tx<0||ty<0||tx>=n||ty>=m||!grid[tx][ty])
{
cn++;
}
}
ans+=cn;
}
}
}
return ans;
}
};