天天看点

[Leetcode] 361. Bomb Enemy 解题报告

题目:

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)      

思路:

据说这道题目必须写出时间复杂度是O(m*n)的算法才算过(m是grid的行个数,n是grid的列个数)。我开始想到的解法是比较原始的动态规划,即定义四个二维数组left,right,up,down,分别表示它的某一个方向可以炸死多少个敌人,例如left[i][j]就表示如果在位置(i, j)放置一颗炸弹,可以炸死的左侧的敌人个数;right,up和down的含义类似。计算这四个二维数组可以用动态规划,花费的时间复杂度是O(m*n)。最后再用一个两重循环确定max(left[i][j] + right[i][j] + up[i][j] + down[i][j])。然而这里的空间复杂度高达O(4*m*n),显得很笨拙。

在网上看到一个很巧妙的算法,可以将空间复杂度降低到O(n)(当然再较真的话还可以降低到O(min(m, n)))。具体做法是:用二重循环遍历grid的时候,如果发现该格子处于第一行或者该格子的上面一个格子是墙,那么就把从该位置到下方第一个墙(或者边界)之间的敌人数目统计出来并且记录下来;同理,如果发现该格子处于第一列或者该格子的左边一个格子是墙,那么就把从该位置到右方第一个墙(或者边界)之间的敌人数目统计出来并且记录下来。之后如果发现该位置是空位置,说明可以放炸弹,就更新最终结果。该方法的巧妙之处在于每个纵区间和每个横区间内的敌人个数只会被统计一次。因此虽然在代码中两重循环内部还有一重循环,但是由于有if条件语句的存在,实际上总的时间复杂度仍然是O(m*n)。

代码:

class Solution {
public:
    int maxKilledEnemies(vector<vector<char>>& grid) {
        if(grid.size() == 0 || grid[0].size() == 0) {
            return 0;
        }
        int row = grid.size(), col = grid[0].size(), rowHits, colHits[col], ans = 0;  
        for(int i = 0; i < row; ++i) {  
            for(int j = 0; j < col; ++j) {  
                if(i == 0 || grid[i-1][j]=='W') {   // update colHits[j] only if the row starts from 0 or the up element is 'W'
                    colHits[j] = 0;  
                    for(int k = i; k < row && grid[k][j]!='W'; ++k) { 
                        colHits[j] += (grid[k][j] == 'E');  
                    }
                }  
                if(j == 0 || grid[i][j-1] == 'W') { // update rowHits only if the col start from 0 or the left element is 'W'
                    rowHits = 0;  
                    for(int k = j; k < col && grid[i][k]!='W'; ++k) { 
                        rowHits += (grid[i][k] == 'E');  
                    }
                }  
                if(grid[i][j] == '0') {
                    ans = max(ans, colHits[j] + rowHits);  
                }
            }  
        }  
        return ans;
    }
};