Lintcode 677
已知:
给一个布尔类型的二维数组, 0 表示海, 1 表示岛。如果两个1是相邻的,那么我们认为他们是同一个岛.我们只考虑 上下左右 相邻.
找到大小在 k 及 k 以上的岛屿的数量
示例:
给一个二维数组:
[
[1, 1, 0, 0, 0],
[0, 1, 0, 0, 1],
[0, 0, 0, 1, 1],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 1]
]
给出 K = 2
返回 2
思路:
题目本身题意还是很清晰的,还有一个简化版的求岛的数量的题目。这一类题目一般来说无论是深度优先还是广度优先算法都是可以实现的。当然,深度优先需要解决环的问题,且需要记住每一次的节点,选定方向,这些操作用基础的代码实现是比较麻烦的。因此我是用的是广度优先的算法。
① 找到一个值为true的值的下标(我的实际实现是从上往下从左往右找到第一个),如果这一步找不到,则返回值为0
② 将当前位的true变为false,并且检测当前位置的上下左右四个方向是否有true,如果有,则调用当前函数处理该位置
③ 重复第二步,返回1 + 四个方向处理的值,如果四个方向都为false或者取不到,则返回1
代码如下:
public class Solution {
//因为可能有多个岛,递归函数用来传递岛的大小了,没地方传递岛本身
//所以将岛的数据放在类中,给所有方法共享
boolean[][] island = null;
public int numsofIsland(boolean[][] grid, int k) {
int ret = 0;
this.island = grid;
//如果岛找不到了,跳出循环
//否则如果岛大小>=k,返回值+1,继续循环
while (true) {
int[] temp = hasIsland(island);
if (temp[0] == -1 && temp[1] == -1) {
break;
}
if (calculate(temp[0], temp[1]) >= k) {
ret++;
}
}
return ret;
}
//广度优先的实现,用类似递归的方式, ij为起始点的下标
//因为每次函数会把当前位变为false,因此不用担心重复计算
private int calculate(int i, int j) {
int ret = 1;
island[i][j] = false;
if (i >= 1 && island[i - 1][j]) {
ret += calculate(i - 1, j);
}
if (i < island.length - 1 && island[i + 1][j]) {
ret += calculate(i + 1, j);
}
if (j >= 1 && island[i][j - 1]) {
ret += calculate(i, j - 1);
}
if (j < island[i].length - 1 && island[i][j + 1]) {
ret += calculate(i, j + 1);
}
return ret;
}
//返回值为true的下标,如果找不到,返回{-1,-1}
private int[] hasIsland(boolean[][] grid) {
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if (grid[i][j]) {
return new int[] { i, j };
}
}
}
return new int[] { -1, -1 };
}
}
谢谢您的阅读~其实这个题目让我纠结了一些时间,有一些畏难情绪,导致才写出代码,其实转过身发现,代码本身的思路并不难,大方向也不难写,细节方面可能需要斟酌,但是其实也用不到多少时间~希望对您有所帮助~