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 ...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?
這道題好像之前在地里面見過,忘了是哪家公司的面試題了,現在被 LeetCode 收錄了,感覺現在 LeetCode 更新越來越快了,感覺要成為第一大題庫了,贊一個👍。這道題讓求戰艦的個數,所謂的戰艦就是只能是一行或者一列,不能有拐彎。這道題降低了難度的做法是限定了不會有相鄰的兩個戰艦的存在,有了這一點限制,那么只需要遍歷一次二維數組就行了,只要找出戰艦的起始點。所謂的戰艦起始點,就是為X的點,而且該點的上方和左邊的點不能為X,所以只要找出所有滿足這個條件的點即可,參見代碼如下:
解法一:
class Solution { public: int countBattleships(vector<vector<char>>& board) { if (board.empty() || board[0].empty()) return 0; int res = 0, m = board.size(), n = board[0].size(); for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (board[i][j] == '.' || (i > 0 && board[i - 1][j] == 'X') || (j > 0 && board[i][j - 1] == 'X')) continue; ++res; } } return res; } };
然而博主自己在做的時候並沒有注意到題目中限制了兩艘戰艦不能相鄰的情況,博主加上了處理方法,首先算出來了所有連續X的區域的個數,方法跟之前那道 Number of Islands 一樣,稍有不同的是,這里分別記錄下來每一個連續區域的i和j,把所有的點的橫縱坐標分別或了起來,這樣做的好處是如果是在一條直線上的戰艦,那么所有點肯定是要么橫坐標都相同,要么縱坐標都相同,所以最后檢測如果橫縱坐標的累積或都跟之前的i和j不同的話,那么一定不是題目中定義的戰艦,那么就不累加結果 res,參見代碼如下:
解法二:
class Solution { public: int countBattleships(vector<vector<char>>& board) { if (board.empty() || board[0].empty()) return 0; int m = board.size(), n = board[0].size(), res = 0; vector<vector<bool>> visited(m, vector<bool>(n, false)); for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (board[i][j] == 'X' && !visited[i][j]) { int vertical = 0, horizontal = 0; dfs(board, visited, vertical, horizontal, i, j); if (vertical == i || horizontal == j) ++res; } } } return res; } void dfs(vector<vector<char>>& board, vector<vector<bool>>& visited, int& vertical, int& horizontal, int i, int j) { int m = board.size(), n = board[0].size(); if (i < 0 || i >= m || j < 0 || j >= n || visited[i][j] || board[i][j] == '.') return; vertical |= i; horizontal |= j; visited[i][j] = true; dfs(board, visited, vertical, horizontal, i - 1, j); dfs(board, visited, vertical, horizontal, i + 1, j); dfs(board, visited, vertical, horizontal, i, j - 1); dfs(board, visited, vertical, horizontal, i, j + 1); } };
既然 DFS 能實現,那么 BFS 就應該沒啥問題,這里完全按題目的要求,默認兩個戰艦不會相鄰,並沒有添加解法二中的過濾條件,參見代碼如下:
解法三:
class Solution { public: int countBattleships(vector<vector<char>>& board) { if (board.empty() || board[0].empty()) return 0; int res = 0, m = board.size(), n = board[0].size(); vector<vector<bool>> visited(m, vector<bool>(n, false)); vector<vector<int>> dirs{{0,-1},{-1,0},{0,1},{1,0}}; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (board[i][j] == 'X' && !visited[i][j]) { ++res; queue<pair<int, int>> q; q.push({i, j}); while (!q.empty()) { auto t = q.front(); q.pop(); visited[t.first][t.second] = true; for (auto dir : dirs) { int x = t.first + dir[0], y = t.second + dir[1]; if (x < 0 || x >= m || y < 0 || y >= n || visited[x][y] || board[x][y] == '.') continue; q.push({x, y}); } } } } } return res; } };
Github 同步地址:
https://github.com/grandyang/leetcode/issues/419
參考資料:
https://leetcode.com/problems/battleships-in-a-board/
https://leetcode.com/problems/battleships-in-a-board/discuss/90902/Simple-Java-Solution
