2257. 统计网格图中没有被保卫的格子数、检索标记

暴力版本:

直接使用一个二维数组保存、墙、护卫的信息。在保存护卫的信息时,处理这个护卫东西南北个个方向的方格,最后计算未被保卫的方格数。

class Solution {
public:
    int countUnguarded(int m, int n, vector<vector<int>>& guards, vector<vector<int>>& walls) {
        /*
        优化部分:
        // 记录已经被护卫访问的行和列
        // 行
        int visitedM[m];
        // 列
        int visitedN[n];
        */

        // 二维方格
        int cell[m][n];

        // 初始化方格
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                // 方格默认值
                cell[i][j] = 0;   
            }
        }        
  
        /*
        优化部分:  
        // 行未访问的标示值
        for(int i = 0; i < m; i++){
            visitedM[i] = 0;
        }

        // 列未访问的标识值
        for(int j = 0; j < n; j++){
            visitedN[j] = 0;
        }
        */

        // 填充墙的信息
        for(int i = 0; i < walls.size(); i++){
            // 墙的标示值
            cell[walls[i][0]][walls[i][1]] = 1;
        }
        
        // 填充护卫的信息,并且填充被保卫地区的信息
        for(int k = 0; k < guards.size(); k++){
            int i = guards[k][0], j = guards[k][1];
            
            // 护卫的标示值
            cell[i][j] = 2;
            
            /*
            优化部分:  
            // 行、列被访问的标识值
            visitedM[i] = 1;
            visitedN[j] = 1;
            */

            // 填充被保卫地区的信息
            // 处理护卫的北边
            int ii = i - 1;
            while(ii >= 0){
                /* 如果当前访问的位置:
                        1.是墙的位置,则停止访问
                */
                if(cell[ii][j] == 1){
                    break;
                }
                
                // 标记被保卫的地区
                cell[ii--][j] = 3;
            }

            // 处理护卫的南边
            ii = i + 1;
            while(ii < m){
                if(cell[ii][j] == 1){
                    break;
                }
                
                cell[ii++][j] = 3;
            }

            // 处理护卫的西边
            int jj = j - 1;
            while(jj >= 0){
                if(cell[i][jj] == 1){
                    break;
                }
                
                cell[i][jj--] = 3;
            }

            // 处理护卫的东边
            jj = j + 1;
            while(jj < n){
                if(cell[i][jj] == 1){
                    break;
                }
                
                cell[i][jj++] = 3;
            }
        }
        
        // 计算未被保卫的方格个数
        int ans = 0;
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                if(cell[i][j] == 0){
                    ans++;
                }
            }
        } 
        
        return ans;
    }
};

优化版本: 

较前一个版本,这里我们主要将优化点放在 “护卫东西南北个个方向的方格” 这段程序。分析我们可以知道,这段程序会有许多重复的工作。

分析如下:

例如当一个护卫在其四个方向中,如果某个方向遇到另一个护卫,其实这个时候当前的护卫可以停止对这个方向的访问;

例如当一个护卫在其四个方向中,如果某个方向遇到已经被保卫的位置,且当前访问方向(某一行或列)已经被另一个护卫访问,且该位置垂直方向(某一列或行)没有被另一个护卫访问,其实这个时候当前的护卫也可以停止对这个方向的访问;

// 优化版本
class Solution {
public:
    int countUnguarded(int m, int n, vector<vector<int>>& guards, vector<vector<int>>& walls) {
        // 记录已经被护卫访问的行和列
        // 行
        int visitedM[m];
        // 列
        int visitedN[n];
        
        // 二维方格
        int cell[m][n];

        // 初始化方格
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                // 方格默认值
                cell[i][j] = 0;   
            }
        }        

        // 行未访问的标示值
        for(int i = 0; i < m; i++){
            visitedM[i] = 0;
        }

        // 列未访问的标识值
        for(int j = 0; j < n; j++){
            visitedN[j] = 0;
        }

        // 填充墙的信息
        for(int i = 0; i < walls.size(); i++){
            // 墙的标示值
            cell[walls[i][0]][walls[i][1]] = 1;
        }
        
        // 填充护卫的信息,并且填充被保卫地区的信息
        for(int k = 0; k < guards.size(); k++){
            int i = guards[k][0], j = guards[k][1];
            
            // 护卫的标示值
            cell[i][j] = 2;
            
            // 行、列被访问的标识值
            visitedM[i] = 1;
            visitedN[j] = 1;

            // 填充被保卫地区的信息
            // 处理护卫的北边
            int ii = i - 1;
            while(ii >= 0){
                /* 如果当前访问的位置:
                        1.是另一个护卫的位置,则停止访问
                        2.是墙的位置,则停止访问
                        3.即非护卫也非墙的位置,仅仅是已经被保卫的位置,如果当前位置的行没有被访问 且 当前位置的列被访问,则停止访问
                */
                if(cell[ii][j] == 2 || cell[ii][j] == 1 || (cell[ii][j] == 3 && visitedM[ii] == 0 && visitedN[j] == 1)){
                    break;
                }
                
                // 标记被保卫的地区
                cell[ii--][j] = 3;
            }

            // 处理护卫的南边
            ii = i + 1;
            while(ii < m){
                if(cell[ii][j] == 2 || cell[ii][j] == 1 || (cell[ii][j] == 3 && visitedM[ii] == 0 && visitedN[j] == 1)){
                    break;
                }
                
                cell[ii++][j] = 3;
            }

            // 处理护卫的西边
            int jj = j - 1;
            while(jj >= 0){
                if(cell[i][jj] == 2 || cell[i][jj] == 1 || (cell[i][jj] == 3 && visitedM[i] == 1 && visitedN[jj] == 0)){
                    break;
                }
                
                cell[i][jj--] = 3;
            }

            // 处理护卫的东边
            jj = j + 1;
            while(jj < n){
                if(cell[i][jj] == 2 || cell[i][jj] == 1 || (cell[i][jj] == 3 && visitedM[i] == 1 && visitedN[jj] == 0)){
                    break;
                }
                
                cell[i][jj++] = 3;
            }
        }
        
        // 计算未被保卫的方格个数
        int ans = 0;
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                if(cell[i][j] == 0){
                    ans++;
                }
            }
        } 
        
        return ans;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值