题目:You are given a map in form of a two-dimensional integer grid where 1 represents land and 0 represents water. Grid cells are connected horizontally/vertically (not diagonally). The grid is completely surrounded by water, and there is exactly one island (i.e., one or more connected land cells). The island doesn’t have “lakes” (water inside that isn’t connected to the water around the island). One cell is a square with side length 1. The grid is rectangular, width and height don’t exceed 100. Determine the perimeter of the island.
链接
解题思路,首先看到题目中说到只有1个岛,这是很关键的地方,大大的简化了题目难度。所以为了求解该岛的周长,我们只需要考虑数组中为1的元素与周围四个元素之间的对应关系,从而确定其四条边是否为周长还是属于陆地内部。自然就有了下面的方法:
这种方法针对每一个1元素去判断其上下左右四个元素是否为1,然后计算周长。相对比较麻烦,击败了37%的用户。
public static int islandPerimeter(int[][] grid) {
int lenth = 0;
for(int i=0; i<grid.length; i++)
for(int j=0; j<grid[0].length; j++)
{
if(grid[i][j]==1)
{
if(i>0 && grid[i-1][j] == 0)
lenth += 1;
else if(i == 0)
lenth += 1;
if(j>0 && grid[i][j-1] == 0)
lenth += 1;
else if(j == 0)
lenth += 1;
if(i < grid.length-1 && grid[i+1][j] == 0)
lenth += 1;
else if(i == grid.length-1)
lenth += 1;
if(j < grid[0].length-1 && grid[i][j+1] == 0)
lenth += 1;
else if(j == grid[0].length-1)
lenth += 1;
}
}
return lenth;
}
思路二:上面的方法没有考虑到岛和边之间的关系。所以我们改进一下。
//改进了一下边的统计方法,击败73%的用户。不想第一种方法去判断每一个island的周围情况
//而是考虑到若两个island相邻,则有一条公共边,且该边属于陆地内部,而不应该被计算在陆地周长之内。
//所以使用4*island - 2*neighbor即可表示陆地周长。
public static int islandPerimeter1(int[][] grid){
int islands = 0, neighbours = 0;
for(int i=0; i<grid.length; i++)
for(int j=0; j<grid[i].length; j++){
if(grid[i][j] == 1){
islands += 1;
if(i < grid.length-1 && grid[i+1][j] == 1) neighbours += 1;
if(j < grid[i].length-1 && grid[i][j+1] == 1) neighbours += 1;
}
}
return islands*4 - neighbours*2;
}
思路三,在网上还看到了使用DFS(深度优先遍历)方法来解这道题的,这种方法效率很高,可以击败95%的用户。我也准备这两天抽时间看一看DFS相关的东西来掌握这种方法。先不多说,上代码:
public static int islandPerimeter2(int[][] grid) {
if (grid == null) return 0;
for (int i = 0 ; i < grid.length ; i++)
for (int j = 0 ; j < grid[0].length ; j++)
if (grid[i][j] == 1)
return getPerimeter(grid,i,j);
return 0;
}
public static int getPerimeter(int[][] grid, int i, int j){
//接下来这三句判断的作用分别是1,判断该点是否处于边缘,如果是则说明该边是周长边,加一即可
//2,判断相邻点是否为0(水域),如果是则说明该边是周长边,加一即可
//3,判断相邻点是否为-1,这里-1表明该点已被读取,见下面会进行置-1
//这些判断的含义就是如果该点属于上述三种情况则说明已经到了叶子节点,需返回上层节点继续遍历别的点。否则说明该点周围仍然有陆地,可以继续往下遍历。可以调试的时候来看清楚运行过程,方便理解。
if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length) {return 1;}
if (grid[i][j] == 0) {
return 1;
}
if (grid[i][j] == -1) return 0;
int count = 0;
//如果通过了上面的判断,即该点既不是边缘也不是0,也未被访问过,则置-1,表示该点目前已被访问
grid[i][j] = -1;
//分别遍历其上、左、右、下面的元素
count += getPerimeter(grid, i-1, j);
count += getPerimeter(grid, i, j-1);
count += getPerimeter(grid, i, j+1);
count += getPerimeter(grid, i+1, j);
return count;
}