包围区域算法的运行时错误

runtime error for algorithm of surrounded region

本文关键字:运行时错误 算法 区域 包围      更新时间:2023-10-16

我想出了一个算法来解决发布在leetcode上的被包围区域问题。

但可悲的是,我的解决方案可以通过第一个判断输入集,但不能通过第二个较大的输入集,并且它报告了运行时错误。然而,我可以在我的笔记本电脑上成功运行!我花了几个小时在这个问题上,但我仍然不知道!

下面是问题

给定一个包含"X"answers"O"的2D板,捕捉所有被"X"包围的区域。

通过将被包围区域中的所有"O"翻转为"X"来捕捉区域。

例如,

X X X

X O O X

X X O X

X O X

运行完您的功能后,板应该是:

X X X

X X X

X X X

X O X

以下是我的解决方案:

class Solution {
public:
    void solve(vector<vector<char> > &board) {
      if(board.size() == 0) return;
      int row = board.size();
      set<pair<int, int> > map;
      for(int i=0; i<= row/2; i++){
         int bottom = row-i-1;
         for(int j=i; j<= bottom; j++){
            checkPoint(board, i, j, map);
            checkPoint(board, bottom, j, map);
            checkPoint(board, j, i, map);
            checkPoint(board, j, bottom, map);
         }
      }        
   }
  void mark(vector<vector<char> >& board, int row, int col, set<pair<int, int> >& map){
      if(row < 0 || row > board.size()-1 || col < 0 || col > board[0].size()-1 )
          return;
    int temp = col;
    while(temp-1 >= 0 && board[row][temp-1] == 'O' &&
        map.find(pair<int,int>(row, temp-1)) ==   map.end()){
        map.insert(pair<int, int>(row, temp-1));
        temp -=1;
        mark(board, row, temp, map);
    }
    temp = col;
    while(temp+1 <= board[0].size()-1 && board[row][temp+1] == 'O' && 
        map.find(pair<int,int>(row, temp+1)) == map.end()){
        map.insert(pair<int, int>(row, temp+1));
        temp +=1;
        mark(board, row, temp, map);
    }
    temp = row;
    while(temp -1 >= 0 && board[temp-1][col] == 'O'&& 
         map.find(pair<int,int>(temp-1, col)) == map.end()){
        map.insert(pair<int, int>(temp-1, col));
        temp -=1;
        mark(board, temp, col, map);
    }
    temp = row;
    while(temp+1 <= board.size()-1 && board[temp+1][col] == 'O'&& 
         map.find(pair<int,int>(temp+1, col)) == map.end()){
        map.insert(pair<int, int>(temp+1, col));
        temp +=1;
        mark(board, temp, col, map);
    }          
 }
  void checkPoint(vector<vector<char> >& board, int row, int col, set<pair<int, int> >& map){
     if(board[row][col] == 'O'){
       if(row ==0 || col== 0 || row == board.size()-1 || col == board[0].size()-1 ){
           if(map.find(pair<int, int>(row, col)) == map.end()){
               map.insert(pair<int,int>(row, col));
               mark(board, row, col, map);
           }
       }else if(map.find(pair<int, int>(row, col)) == map.end()){
              board[row][col] = 'X';
      }
    }
    return;
  }
};

我同意另一个答案,要么是使用了太多的运行时,要么是堆栈空间。试试这个主意。请注意,对于"O"的连接区域,该区域要么接触到板的边缘,要么完全被"X"包围。因此,您可以使用以下策略。首先沿着木板的边缘走,直到你找到一个"O"。然后将一个集合CurrentBoundaryO初始化为等于这一个"O"的集合,并将一个集NextBoundary0初始化为空。然后反复执行以下操作。将CurrentBoundaryO中的每个位置标记为"未更改的O"。然后遍历CurrentBoundaryO的元素并检查所有邻居。每个为"O"但未标记为"未更改O"的邻居都应添加到集合NextBoundaryO中。然后将CurrentBoundaryO设置为NextBoundary0并重复,直到CurrentBoundryO没有元素为止。然后继续在板的边缘搜索,直到找到一个没有标记为"未更改的O"的"O",然后重复该过程。不断重复,直到你沿着木板的整个边缘行进。那么每个"X"仍然是"X",每个标记为"不变的O"的"O"仍然是一个"O",并且板上的所有其他"O"都应该切换到"X"。根据输入大小,该策略在线性时间内运行,并且避免了递归,因此也不存在堆栈空间问题。这应该通过评委软件评估。

通常,在线评委在与桌面上完全不同的环境中运行。服务器使用商品硬件,这意味着cpu可能很慢,内存也很小。没有什么可以阻止您的代码在线程中运行。此外,您无法控制优化级别和使用的编译器。

该错误可能是由于mark函数的递归性质造成的运行时错误imho要么是由于堆栈溢出,要么是由于程序因花费太多时间而终止

函数标记是非常不直观和昂贵的。首先,它是递归的,最大深度与板的尺寸成线性关系。如果董事会有100万行,我们将有

mark(1000000,...)   
  mark(1000000-1,...)
    ...
      mark(1,...) 
        mark(0,...)

堆栈可能不够大。

其次,每次调用时,都会将同一行或列中的每个单元格标记为"已访问"(map.find(pair<int,int>(x, y)) == map.end()),次数比所需次数多。假设网格是nxn。如果你调用标记(x,y),上面的测试将对x行和y行上的每个位置进行n次。这意味着标记的复杂性是O(n^2)。通常,它是O(#行^2+#列^2)

然后你有:

 for(int i=0; i<= row/2; i++){
     int bottom = row-i-1;
     for(int j=i; j<= bottom; j++){
        checkPoint(board, i, j, map);         <--O(n^2)
        checkPoint(board, bottom, j, map);    <--O(n^2)
        checkPoint(board, j, i, map);         <--O(n^2)
        checkPoint(board, j, bottom, map);    <--O(n^2)
     }
  }

您的代码具有最差的运行时间O(n^4),其中n=max(row,cols)。

ps:我是怎么想到马克的复杂性的?

board[row][y-1] = 'O'标记(x,y),引导

  mark(x,y-1)
  mark(x,y-2)
  ...
  mark(x,0)

在每个标记中,再次测试整个行。其对函数CCD_ 5进行n次调用。因此,n^2的复杂性。