Given a 2D grid, each cell is either a wall 'W'
, an enemy 'E'
or empty '0'
(the number zero), return the maximum enemies you can kill using one bomb.
The bomb kills all the enemies in the same row and column from the planted point until it hits the wall since the wall is too strong to be destroyed.
Note that you can only put the bomb at an empty cell.
Example:
For the given grid 0 E 0 0 E 0 W E 0 E 0 0 return 3. (Placing a bomb at (1,1) kills 3 enemies)
Credits:
Special thanks to @memoryless for adding this problem and creating all test cases.
這道題相當於一個簡單的炸彈人游戲,讓博主想起了小時候玩的紅白機的炸彈人游戲(小霸王學習機,其樂無窮!!),放一個炸彈,然后爆炸后會炸出個‘十’字,上下左右的東西都炸掉了。這道題是個簡化版,字母E代表敵人,W代表牆壁,這里說明了炸彈無法炸穿牆壁。數字0表示可以放炸彈的位置,讓找出一個放炸彈的位置可以炸死最多的敵人。那么博主最開始想出的方法是建立四個累加數組 v1, v2, v3, v4,其中 v1 是水平方向從左到右的累加數組,v2 是水平方向從右到左的累加數組,v3 是豎直方向從上到下的累加數組,v4 是豎直方向從下到上的累加數組,建立好這個累加數組后,對於任意位置 (i, j),其可以炸死的最多敵人數就是 v1[i][j] + v2[i][j] + v3[i][j] + v4[i][j],最后通過比較每個位置的累加和,就可以得到結果,參見代碼如下:
解法一:
class Solution { public: int maxKilledEnemies(vector<vector<char>>& grid) { if (grid.empty() || grid[0].empty()) return 0; int m = grid.size(), n = grid[0].size(), res = 0; vector<vector<int>> v1(m, vector<int>(n, 0)), v2 = v1, v3 = v1, v4 = v1; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { int t = (j == 0 || grid[i][j] == 'W') ? 0 : v1[i][j - 1]; v1[i][j] = grid[i][j] == 'E' ? t + 1 : t; } for (int j = n - 1; j >= 0; --j) { int t = (j == n - 1 || grid[i][j] == 'W') ? 0 : v2[i][j + 1]; v2[i][j] = grid[i][j] == 'E' ? t + 1 : t; } } for (int j = 0; j < n; ++j) { for (int i = 0; i < m; ++i) { int t = (i == 0 || grid[i][j] == 'W') ? 0 : v3[i - 1][j]; v3[i][j] = grid[i][j] == 'E' ? t + 1 : t; } for (int i = m - 1; i >= 0; --i) { int t = (i == m - 1 || grid[i][j] == 'W') ? 0 : v4[i + 1][j]; v4[i][j] = grid[i][j] == 'E' ? t + 1 : t; } } for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (grid[i][j] == '0') { res = max(res, v1[i][j] + v2[i][j] + v3[i][j] + v4[i][j]); } } } return res; } };
在論壇里看到了史蒂芬大神提出的另一種解法,感覺挺巧妙,就搬了過來。這種解法比較省空間,寫法也比較簡潔,需要一個 rowCnt 變量,用來記錄到下一個牆之前的敵人個數。還需要一個數組 colCnt,其中 colCnt[j] 表示第j列到下一個牆之前的敵人個數。算法思路是遍歷整個數組 grid,對於一個位置 grid[i][j],對於水平方向,如果當前位置是開頭一個或者前面一個是牆壁,開始從當前位置往后遍歷,遍歷到末尾或者牆的位置停止,計算敵人個數。對於豎直方向也是同樣,如果當前位置是開頭一個或者上面一個是牆壁,開始從當前位置向下遍歷,遍歷到末尾或者牆的位置停止,計算敵人個數。可能會有人有疑問,為啥 rowCnt 就可以用一個變量,而 colCnt 就需要用一個數組呢,為啥 colCnt 不能也用一個變量呢?原因是由遍歷順序決定的,這里是逐行遍歷的,在每行的開頭就統計了該行的敵人總數,所以再該行遍歷沒必要用數組,但是每次移動時就會換到不同的列,總不能沒換個列就重新統計一遍吧,所以就在第一行時一起統計了存到數組中供后來使用。有了水平方向和豎直方向敵人的個數,那么如果當前位置是0,表示可以放炸彈,更新結果 res 即可,參見代碼如下:
解法二:
class Solution { public: int maxKilledEnemies(vector<vector<char>>& grid) { if (grid.empty() || grid[0].empty()) return 0; int m = grid.size(), n = grid[0].size(), res = 0, rowCnt, colCnt[n]; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (j == 0 || grid[i][j - 1] == 'W') { rowCnt = 0; for (int k = j; k < n && grid[i][k] != 'W'; ++k) { rowCnt += grid[i][k] == 'E'; } } if (i == 0 || grid[i - 1][j] == 'W') { colCnt[j] = 0; for (int k = i; k < m && grid[k][j] != 'W'; ++k) { colCnt[j] += grid[k][j] == 'E'; } } if (grid[i][j] == '0') { res = max(res, rowCnt + colCnt[j]); } } } return res; } };
Github 同步地址:
https://github.com/grandyang/leetcode/issues/361
參考資料:
https://leetcode.com/problems/bomb-enemy/
https://leetcode.com/problems/bomb-enemy/discuss/83387/short-omn-time-on-space-solution