题目:
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) orNx1(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 ...XIn the above board there are 2 battleships.
Invalid Example:
...X XXXX ...XThis 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?
思路:
这道题目完全可以用union-find来解决,不过由于battleship的特殊形式,用union-find似乎有点杀鸡用牛刀。实际上我们可以用更简单的方法来实现:如果按照从左到右,从上到下的顺序遍历这个方格,那么对于每个battleship,我们首先一定会遇到它的舰首,每当遇到一个舰首时,我们一方面更新ret值,另一方面将该舰的其余部分全部置为‘.’,这样可以。避免后面的重复计算。这种方法算是one-pass,也没有使用额外的存储空间,但是在运行的过程中改变了board的值。
在Follow up中问我们是否能够不修改board的值?答案是可以的:我们每次碰到一个‘X’,首先判断该位置是不是舰首,如果是舰首,则ret值更新;否则说明该舰在前面已经被计算过了,直接跳过。Follow up的代码我就不上了,有兴趣的读者可以自己在下面代码的基础上实现。
代码:
class Solution {
public:
int countBattleships(vector<vector<char>>& board) {
if (board.size() == 0 || board[0].size() == 0) {
return 0;
}
int row_num = board.size(), col_num = board[0].size();
int ret = 0;
for (int y = 0; y < row_num; ++y) {
for (int x = 0; x < col_num; ++x) {
if (board[y][x] == 'X') {
++ret;
removeBattleShip(board, x, y);
}
}
}
return ret;
}
private:
void removeBattleShip(vector<vector<char>> &board, int x, int y) {
int row_num = board.size(), col_num = board[0].size();
board[y][x] = '.';
while (x < col_num - 1 && board[y][x + 1] == 'X') {
board[y][++x] = '.';
}
while (y < row_num - 1 && board[y + 1][x] == 'X') {
board[++y][x] = '.';
}
}
};
本文介绍了一种高效算法,用于在一维数组表示的棋盘上计数战舰数量。通过一次遍历并利用特定规则标记战舰头部,避免了重复计算,实现了O(1)额外空间复杂度。
417

被折叠的 条评论
为什么被折叠?



