LeetCode之路:463. Island Perimeter

来源:互联网 发布:java中flag的用法 编辑:程序博客网 时间:2024/06/05 07:14

一、引言

这道题的题目信息请点击这里查看Island Perimeter。

其实我一看到这道题,我就想到了我之前做过的一个五子棋的项目。关于这个项目我还写了一篇博客,可以点击这里查看一个使用纯Win32 SDK和C语言实现的五子棋游戏。

这里让我们想想,五子棋的判胜逻辑。

五子棋五子棋,顾名思义,就是五个同色的棋子连接成了一条线,则判定胜利。那么五子棋的判胜逻辑应该怎么完成呢?

这里进行简要的总结:其实主要的核心思想就是以一个棋子为观察原点,我们以这个棋子出发,观察八个方向(包括四个斜方向)是否存在同色棋子,然后递归计数即可。

回到这道题,其实我们以一个 island 为中心,观察它附近是否存在 island,如果存在,则周长 -1 即可。

二、我的代码

这里我再来总结下思路:
1. 遍历整个 grid,找到其中所有的 island,也就是值为 1 的点
2. 以这个点为中心,检测它附近是否有 island,也就是检测它附近的四个方向的点(上下左右)是否值为 1。这里我们假想一下,其实很简单,只要有一个相邻的 island,周长就会减少 1,最后我们将每个 island 的周长计数加起来即可。
3. 将每个 island 的周长计数加起来即可。

代码如下:

class Solution {public:    struct point {        unsigned x;        unsigned y;    };    int validSideCount(const point &pt, vector<vector <int>> &grid) {        int validSideCount = 0;        if (pt.x == 0 || grid[pt.x - 1][pt.y] == 0) {            ++validSideCount;        }        if (pt.x == grid.size() - 1 || grid[pt.x + 1][pt.y] == 0) {            ++validSideCount;        }        if (pt.y == 0 || grid[pt.x][pt.y - 1] == 0) {            ++validSideCount;        }        if (pt.y == grid[0].size() - 1 || grid[pt.x][pt.y + 1] == 0) {            ++validSideCount;        }        return validSideCount;    }    int islandPerimeter(vector<vector<int>> &grid) {        int islandPerimeter = 0;        for (int row = 0; row < grid.size(); ++row) {            for (int col = 0; col < grid[row].size(); ++col) {                if (grid[row][col] == 1) {                    point pt = { row, col };                    islandPerimeter += validSideCount(pt, grid);                }            }        }        return islandPerimeter;    }};

这里,我声明了一个 point 类,方便记录当前 island 的坐标。validSideCount 函数的作用就是用来检测 island 附近是否存在值为 1 的点,计数一个 island 的周长,要获得所有 island 的周长,只需要将所有的 island 的周长计数加起来即可。

这里需要注意的是,validSideCount 函数中这四个判定,需要检测是否碰到了边(坐标不能超出 vector 的最大范围值),如果碰到了边,则不能进行递减或者递增操作了,这样会出现数组访问溢出错误。

三、同样,赏析一段别人的代码

直接上代码吧,写完自己的,总是要看看别人的代码为什么比自己的代码优美不是?

int islandPerimeter(vector<vector<int>>& grid) {        int count=0, repeat=0;        for(int i=0;i<grid.size();i++)        {            for(int j=0; j<grid[i].size();j++)                {                    if(grid[i][j]==1)                    {                        count ++;                        if(i!=0 && grid[i-1][j] == 1) repeat++;                        if(j!=0 && grid[i][j-1] == 1) repeat++;                    }                }        }        return 4*count-repeat*2;    }

这段代码要点如下:
1. 利用了两个变量进行周长计数:

其中,count 用来计数 island 的个数, repeat 用来计数两个 island 相邻(两个 island 相邻必然导致两条周长的减少)的个数。

那么 count * 4 - repeat * 2必然就是最终的周长,其中 repeat 的计算只计算了当前 island 的上方和左方的记录,因为下方和右方的损失也已经包括在相对方里面去了,这里就不用再多判断了,只需要乘以2即可。

  1. 我发现外国人写代码,很喜欢将很短小的代码块放到一行书写,比如这里的两个判断语句:
if(i!=0 && grid[i-1][j] == 1) repeat++;if(j!=0 && grid[i][j-1] == 1) repeat++;

要是我来写,准得写成这样:

if (i != 0 && grid[i - 1][j == 1) {    repeat++;}if (j != 0 && grid[i)[j - 1] == 1) {    repeat++;}

其实孰优孰劣一目了然,前者真的是一目了然,而我看似在认真的遵循着编码习惯,实则扰乱了眼球,让代码阅读者一眼看不到重点。

三、总结

总结就这么多,从这道题,又看到了一点点当初写五子棋游戏的影子;同时也看到了不一样的代码风格。

让我们的代码更加 elegant 吧!

0 0
原创粉丝点击