LeetCode刷题 463. Island Perimeter 岛屿的周长 Java

题目介绍

链接:https://leetcode-cn.com/problems/island-perimeter

给定一个包含 0 和 1 的二维网格地图,其中 1 表示陆地 0 表示水域。

网格中的格子水平和垂直方向相连(对角线方向不相连)。整个网格被水完全包围,但其中恰好有一个岛屿(或者说,一个或多个表示陆地的格子相连组成的岛屿)。

岛屿中没有“湖”(“湖” 指水域在岛屿内部且不和岛屿周围的水相连)。格子是边长为 1 的正方形。网格为长方形,且宽度和高度均不超过 100 。计算这个岛屿的周长。
示例图片如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UlylF93Q-1604059924346)(岛屿示例图片.jpg)]


题目分析

二维数组代替一个地图区域,0表示水域1表示小岛,所有水域都是联通集。

题目的要求主要就是实现对二维数组中上下左右相邻元素数值的判断,因为一旦相邻就会造成两者结合部分的消失。


解法一

解题思路

从图中看到所有的小岛,或者说所有的相邻元素之间存在的状态只可能是四种情况。

  1. 单独的一个单位为1的小岛,那么他会贡献小岛总的长度为4的四个边长
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g20XuSXc-1604059924348)(没有相邻边.png)]

  2. 当前小岛只有一个边会与另外一个小岛相接,那么当前的小岛会贡献其余的三个边作为总的边长
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1mWxeH3d-1604059924349)(一边相连.png)]

  3. 当前小岛有两个方向与其他小岛相接,会贡献其余的两边给整个小岛的周长
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R57kpLSw-1604059924353)(两边相连.png)]

  4. 当前小岛有三个方向与其他小岛相接,剩余的一条边会作为整个小岛的周长
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T5XtSeeh-1604059924354)(三边相连.png)]在这里插入图片描述

  5. 当前小岛所有相邻方向全与别的小岛相接,成为一个内陆部分不贡献自己的任何边
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PaHnusLx-1604059924355)(四边相连.png)]


因此只要遍历数组中**所有种类小岛个数**,根据各种类会贡献的周长就可以算出小岛周长总和。

具体代码

class Solution {
    public int islandPerimeter(int[][] grid) {
        int n = grid.length;
        int m = grid[0].length;
        int ans=0;
        int [] dx={0,1,0,-1};//位移数组
        int [] dy={1,0,-1,0};//分别访问当前元素下,右,上,左位置
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(grid[i][j]==0){
                    continue;//不是小岛元素直接continue
                }//底下是小岛单位
                int count=0//count记录当前小岛上下左右四个位置是否有相邻
                for(int k=0;k<dx.length;k++){//循环判断上下左右元素值
                    int nx = i+dx[k];
                    int ny = j+dy[k];
                    if(nx>=0&&nx<n&&ny>=0&&ny<m&&grid[nx][ny]==1)
                        count++;
                }
                switch(count){//当前单位小岛相邻位置判断结束,根据count计算最终结果
                    case 0 :ans+=4;break; 
                    case 1 :ans+=3;break;
                    case 2 :ans+=2;break;
                    case 3 :ans+=1;break;
                    case 4 :ans=ans;break;
                }
            }
        }
        return ans;
    }
}

解法二

解题思路

  • 解法一存在的问题
    思考上一种的解法可以发现,每次遍历的时候是会出现**重复判断**的。也就是在上一行当中已经判断过元素a与下一行的元素b相接,但是到下一行元素b时又会判断是否与上一行的元素a相接。

  • 解决办法
    从第一个元素开始判断是否是岛屿元素,是则直接默认贡献四边的长度count+=4,然后再向右和向下判断是否和其他元素相邻,若相邻一条边则消失两条边的周长count-=2(两条边重合并且都不再是岛屿的边缘)。等于遍历到底部元素时不会在继续判断上方已经判断过的元素。

具体代码

class Solution {
    public int islandPerimeter(int[][] grid) {
        int n = grid.length;
        int m = grid[0].length;
        int count=0;//记录总的小岛边数
        int [] dx={0,1};//位移数组,向右享下
        int [] dy={1,0};
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(grid[i][j]==0){
                    continue;//不是小岛元素直接continue
                }
                count+=4;//时元素默认直接时单独的,再继续向右向下判断
                for(int k=0;k<dx.length;k++){
                    int nx = i+dx[k];
                    int ny = j+dy[k];
                    if(nx<n&&ny<m&&grid[nx][ny]==1)//判断相邻右和下是否是小岛元素
                        count-=2;//相邻一条边,减去最终的两条边
                }

            }
        }
        return count;
    }
}

一点思考

因为题目当前限定的是一个相连再一起的岛屿,不会存在类似与两个单独空心湖泊存在的情况。那么就一定确保了岛屿在四个面方向上**对立面个数总是相同的**。比如说岛屿的左面有三个面就一定确保了右面也只有三个面,能否只通过检测两个对立面中的其中一个方向获取总的岛屿周长呢?大家一起交流讨论把。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值