LeetCode刷题记录(第十三天)

5 篇文章 0 订阅

Island Perimeter

原题目:

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代表土地,0代表水。网格单元格水平/垂直连接(不是对角线)。网格完全被水包围,并且恰好有一个岛(即,一个或多个连接的陆地单元)。该岛没有“湖泊”(里面的水没有连接到岛上的水)。一个单元格是边长为1的正方形。网格是矩形的,宽度和高度不超过100.确定岛的周长。

事例:

Example:

[[0,1,0,0],
 [1,1,1,0],
 [0,1,0,0],
 [1,1,0,0]]

Answer: 16
Explanation: The perimeter is the 16 yellow stripes in the image below:

思路:

首先,这道题要计算周长,也就是二维数组中值为1的元素漏在外面的边数。我的一开始的思路是这样的:

1、遍历寻找1;

2、判断它的四周哪里为0,几个面为0,周长加几(最多就是三,因为岛中没有湖);

但是这样有一个问题,需要判断1是否在边界,如果再四个边界上,按照思路中的方法肯定会出现数组越界,所以我又改变了一下判断条件,在第二层判断的时候从第二个值开始,到倒数第二个值结束,而且只判断前一个和后一个值是否为0,是0周长就往上加。但是写完遍历的代码再来处理边界时,发现还是异常的麻烦,需要判断的可能非常多,虽然按照这个思路也可以写出来,但是。。。。呵呵,我还是放弃这个思路了。


其实我想到一个更好的办法,就是我们如果给现在已有的范围在加上一圈水如何?也就是在这个给定的二维数组外面包一圈0,那样就可以按照我上面的思路进行解答了,会非常的方便。但是查了半天找了半天想了半天,还是没有成功,中间使用list,但是最后发现list无法再转换回一个二维数组,还是放弃这个想法了,真的没有思路了,还是去看看大神的代码找找思路学习一下吧:

public int islandPerimeter(int[][] grid) {
    int[][] d = new int[][] {{0,-1}, {-1,0}, {0,1}, {1,0}};
    
    int perimeter = 0;
    for(int i=0; i<grid.length; i++) {
        for(int j=0; j<grid[0].length; j++) {
            if(grid[i][j] == 0)
                continue;
            
            for(int k=0; k<d.length; k++) {
                int x=i+d[k][0], y=j+d[k][1];
                if(x<0 || x>=grid.length || y<0 || y>=grid[0].length || grid[x][y] == 0)
                    perimeter++;
            }
        }
    }
    
    return perimeter;
}

这个方法是真的没有看懂,并不理解为什么要这么做,但是还有一个大神的代码还是比较好理解的:

public static int islandPerimeter(int[][] grid) {
        if (grid == null || grid.length == 0 || grid[0].length == 0) return 0;
        int result = 0;
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (grid[i][j] == 1) {
                    result += 4;
                    if (i > 0 && grid[i-1][j] == 1) result -= 2;
                    if (j > 0 && grid[i][j-1] == 1) result -= 2;
                }
            }
        }
        return result;
    }

这个方法其实一开始也没有懂,但是慢慢的思考,反应,发现还是可以理解的。

首先,遍历找出值为1的土地,直接给周长加4,然后判断它在哪里,只要不在上面的边界和左面的边界上,我们就去看它的上边和左边是不是土地,如果不是,则不管,继续执行,如果出现一面是土地,则周长减二。为什么要减二?因为当土地出现在最上面和最左面的边界时,我们并没有做任何操作,直接给周长加4,所以两个土地挨在一起是少了两个边。肯定还有人在想,那上左都有土地直接减四不就减没了?当然不会了,再后面的遍历中还是直接加4的,所以不用担心边界也不用担心会计算错,这真的算是一个完美的方法,至少我是这么认为的,思路简单清晰易懂,而且只是基本的两次遍历,效率也非常的高。

我只能讲解到这种地步了,如果还是没有理解,可以找来笔和纸,边想边画出来,这样更好理解。当然,如果哪位大神理解第一种方法,希望可以留言教导,谢谢。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值