[Leetcode] 361. Bomb Enemy 解题报告

本文介绍了LeetCode中第361题的解题报告,探讨了如何在2D网格中放置炸弹以消灭最多敌人。通过动态规划方法,实现了O(m*n)时间复杂度的解决方案,降低了空间复杂度。文章详细阐述了优化后的算法思路,避免了重复计算,确保总时间复杂度保持不变。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

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;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值