您的位置:首页 > 其它

[LeetCode] 419. Battleships in a Board 解题报告

2017-02-16 11:49 363 查看
Given an 2D board, count how many battleships are in it. The battleships are represented with
'X'
s,
empty slots are represented with
'.'
s. You may assume the following rules:

You receive a valid board, made of only battleships or empty slots.
Battleships can only be placed horizontally or vertically. In other words, they can only be made of the shape
1xN
(1
row, N columns) or
Nx1
(N rows, 1 column), where N can be of any size.
At least one horizontal or vertical cell separates between two battleships - there are no adjacent battleships.

Example:

X..X
...X
...X

In the above board there are 2 battleships.

Invalid Example:

...X
XXXX
...X

This is an invalid board that you will not receive - as battleships will always have a cell separating between them.

Follow up:

Could you do it in one-pass, using only O(1) extra memory and without modifying the value of the board?

这个题和前面某一个类似,求那个独立岛屿的数量。我看了以后,感觉和上一题417的思路特别像。(我看了网友的解答以后,发现自己的方法蠢酷了,又臭又长,不感兴趣的朋友,请直接跳到方法二)
方法一:
BFS搜索,和上面一题一样的,从左上角开始进行BFS搜索。使用循环和queue,boolean[][],搜索没有ship的格子“.”,然后把这个格子放到queue中,对应位置标记true,取出这个格子,继续循环,直到queue为空。

但是,一旦发现有ship的格子“X”,总和++,然后跳转到另一个函数,对这个格子四个方向的所有“X”格子进行搜索,这时候同样有另一个queue和循环,保证将这一个ship的所有格子都搜索到,并对应位置标记为true。(因为如果不一次性把当前ship对应的所有x找到,那么在后面的搜索中,可能会搜索到这个x,那就不知道这个x对应的ship到底有没有被搜索到。)

最后,返回总和即可。

由于BFS的时候,对于一个格子,搜索的是四个方向的,因此复杂度大约是O(4N),这个方法效率比较差,只打败了1.03%,代码的重用性也很差(我自己想的),不推荐。代码如下:

public class Solution {
char[][] board;
int nHeight;
int nWidth;
boolean[][] bExpl;
int nTotal;
Queue<int[]> queCommon;

public int countBattleships(char[][] board) {
if (board.length == 0||board==null || board[0].length==0) {
return 0;
}
this.board = board;
nHeight = board.length;
nWidth = board[0].length;
bExpl = new boolean[nHeight][nWidth];
queCommon = new LinkedList<int[]>();

// init
bExpl[0][0] = true;
if (board[0][0] == '.') {
queCommon.add(new int[] { 0, 0 });
} else {
nTotal++;
findShip(new int[] { 0, 0 });
}

//explore the common point
while (queCommon.size() > 0) {
int[] nArrCur = queCommon.poll();
// judge the current grid x or .
explore(nArrCur, queCommon);
}

return nTotal;

}

private boolean isBeyond(int x, int y) {
return x >= 0 && y >= 0 && x < nHeight && y < nWidth ? true : false;
}

private void explore(int[] n, Queue<int[]> q) {
int x = n[0];
int y = n[1];
if (isBeyond(x, y - 1)) {
tagNewPoint(x, y - 1, q);
}
if (isBeyond(x, y + 1)) {
tagNewPoint(x, y + 1, q);
}
if (isBeyond(x - 1, y)) {
tagNewPoint(x - 1, y, q);
}
if (isBeyond(x + 1, y)) {
tagNewPoint(x + 1, y, q);
}
}

private void exploreShip(int[] n, Queue<int[]> q) {
int x = n[0];
int y = n[1];
if (isBeyond(x, y - 1)) {
tagNewShip(x, y - 1, q);
}
if (isBeyond(x, y + 1)) {
tagNewShip(x, y + 1, q);
}
if (isBeyond(x - 1, y)) {
tagNewShip(x - 1, y, q);
}
if (isBeyond(x + 1, y)) {
tagNewShip(x + 1, y, q);
}
}

private void findShip(int[] n) {
Queue<int[]> queShip = new LinkedList<int[]>();
queShip.add(n);
while (queShip.size() > 0) {
int[] nArrCur = queShip.poll();
// find all nearby ship
exploreShip(nArrCur, queShip);
}
}

private void tagNewPoint(int x, int y, Queue<int[]> q) {
if (bExpl[x][y] == false) {
bExpl[x][y] = true;
int[] nn = { x, y };
if (board[x][y] == '.') {
q.add(nn);
} else {
nTotal++;
//when meets the ship, and find the whole ship once
findShip(nn);
}
}
}

private void tagNewShip(int x, int y, Queue<int[]> q) {
if (bExpl[x][y] == false) {
bExpl[x][y] = true;
int[] nn = { x, y };
if (board[x][y] == 'X') {
q.add(nn);
} else {
queCommon.add(nn);
}
}
}
}


方法二:

这个方法代码量也少,原理也简单,网友还是机制。

它利用了这个题目的特性,根据题意,任意两个ships都是隔开的;也就是说,不可能存在一个ship,四面相邻另一个ship;再换句话说,由于所有的ship不是横着就是竖着的,所有任意一个ship的左上角第一个格子的上面和左边必然相邻的不是ship,我们只用数一数这样的格子有几个,就知道有几个ship了。

另外,这个方法需要注意的是:在当前格子位于边缘的时候,左边和上面的格子index值为-1,如果这时候再直接取值的话,会出现数组超界的错误。

这个方法大概的复杂度应该是O(2N),代码如下:

public class Solution {
public int countBattleships(char[][] board) {
if (board == null) {
return 0;
}
int nTotal = 0;
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
if (board[i][j] == 'X') {
boolean bI = i == 0 ? true : false;
boolean bJ = j == 0 ? true : false;
if (!bI) {
bI = board[i - 1][j] == '.' ? true : false;
}
if (!bJ) {
bJ = board[i][j - 1] == '.' ? true : false;
}
if (bI && bJ) {
nTotal++;
}
}
}
}
return nTotal;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  2d