暴力版本:
直接使用一个二维数组保存、墙、护卫的信息。在保存护卫的信息时,处理这个护卫东西南北个个方向的方格,最后计算未被保卫的方格数。
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;
}
};