小明思考

          Just a software engineer
          posts - 124, comments - 36, trackbacks - 0, articles - 0
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          包圍的區域

          Posted on 2013-04-15 18:17 小明 閱讀(1562) 評論(2)  編輯  收藏 所屬分類: 數據結構和算法
          問題給定一個2D的棋盤,含有‘X'和’O',找到所有被‘X'包圍的’O',然后把該區域的‘O’都變成'X'。

          例子-輸入:
          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 X X X
          X O X X

          public void solve(char[][] board) {
          }

          分析:
          為了提高效率,我使用了一個mark數組來記錄所有訪問過的‘O'點,避免重復檢查,同時要避免死循環。
          每個點有四種狀態,未檢測(0),正在檢測(-1),包圍的點(1),沒有被包圍的點(2)。
          另外,為了對付很大的棋盤,避免使用遞歸而造成堆棧溢出,使用了一個檢測隊列。

          代碼如下:

          public class SurroundedRegions {
              
              private char[][] board;
              private int[][] mark;
              private int h;
              private int w;
              
              private final int S = 1; //surrounded point
              private final int NS = 2; //Not surrounded point
              private final int T = -1; //testing point, undetermined point
              
              private static class Point{
                  int x,y;
                  
                  Point(int x,int y){
                      this.x =x;
                      this.y = y;
                  }
              }
              
              private int test(int i,int j, List<Point> lp){
                  int result = S;
                  mark[i][j] = T; 
                  if(i==0 || i==h-1 || j==0 || j==w-1){ //border point
                      result = NS;
                  }
                  else{
                      int[] nx={i-1,i,i,i+1};
                      int[] ny={j,j-1,j+1,j};
                      for(int k=0;k<4;++k){ //check the four directions
                          int x = nx[k];
                          int y = ny[k];
                          if(board[x][y]=='O'){
                              int m = mark[x][y];
                              if(m==0){
                                  mark[x][y] = T; //mark as testing point to avoid duplicated visit
                                  lp.add(new Point(x,y));
                              }
                              else if(m>0){
                                  result =  m;
                              }
                          }
                          if(result==NS){
                              break;
                          }
                      }
                  }
                  mark[i][j]= result;
                  return result;
              }
              
              public void solve(char[][] board) {
                  this.h = board.length;
                  if(h<1){
                      return;
                  }
                  this.w = board[0].length;
                  
                  this.board = board;
                  this.mark = new int[h][w];
                  
                  for(int i=0;i<h;++i){
                      char[] row = board[i];
                      int[] mrow = mark[i];
                      for(int j=0;j<w;++j){
                          char c = row[j];
                          if(c=='O' && mrow[j]==0){ //not marked point
                              List<Point> lp = new ArrayList<Point>(); //visit queue
                              lp.add(new Point(i,j));
                              int result = S;
                              for(int k=0;k<lp.size();++k){ //Notice: the size of queue maybe increase during the loop  
                                  Point p = lp.get(k);
                                  if(test(p.x,p.y,lp) == NS){ //once find the NS flag,stop checking
                                      result = NS;
                                      break;
                                  }
                              }
                              for(int k=0;k<lp.size();++k){ //mark  all points in the current visit queue
                                  Point p = lp.get(k);
                                  mark[p.x][p.y] = result;
                              }
                          }
                      }
                  }
                  for(int i=0;i<h;++i){ //flip all marked points
                      char[] row = board[i];
                      int[] mrow = mark[i];
                      for(int j=0;j<w;++j){
                          char c = row[j];
                          if(c=='O' && mrow[j]==S){
                              row[j] ='X';
                          }
                      }
                  }
              }

          ====update====
          改進了一下,從邊開始掃描,找到所有邊上白字相鄰的節點即可解決問題。代碼如下:

          public class SurroundedRegions {

              private char[][] board;
              private int[][] mark;
              private int h;
              private int w;

              private static class Point {
                  int x, y;

                  Point(int x, int y) {
                      this.x = x;
                      this.y = y;
                  }
              }

              private List<Point> extend(int i, int j) {
                  List<Point> lp = new ArrayList<Point>();
                  int[] nx = { i - 1, i, i, i + 1 };
                  int[] ny = { j, j - 1, j + 1, j };
                  for (int k = 0; k < 4; ++k) { // check the four directions
                      int x = nx[k];
                      int y = ny[k];
                      if (x >= 0 && x < h && y >= 0 && y < w && board[x][y] == 'O' && mark[x][y] == 0) {
                          mark[x][y] = 1;
                          lp.add(new Point(x, y));
                      }
                  }
                  return lp;
              }

              public void solve(char[][] board) {
                  this.h = board.length;
                  if (h <= 1) {
                      return;
                  }
                  this.w = board[0].length;

                  this.board = board;
                  this.mark = new int[h][w];

                  int x = 0, y = 0;
                  int[] dxx = { 1, 0, -1, 0 };
                  int[] dyy = { 0, 1, 0, -1 };

                  for (int i = 0; i < 4; ++i) {
                      int dx = dxx[i];
                      int dy = dyy[i];
                      int len = (i % 2 == 0) ? h : w;
                      for (int j = 0; j < len-1; ++j) {
                          char c = board[x][y];
                          if (c == 'O' && mark[x][y] == 0) {
                              List<Point> vq = new ArrayList<Point>(); // visit queue
                              vq.add(new Point(x, y));
                              while (!vq.isEmpty()) {
                                  Point p = vq.remove(vq.size() - 1);
                                  mark[p.x][p.y] = 1;
                                  vq.addAll(extend(p.x, p.y));
                              }
                          }
                          x += dx;
                          y += dy;
                      }
                  }

                  for (int i = 0; i < h; ++i) { // flip all unmarked points
                      char[] row = board[i];
                      int[] mrow = mark[i];
                      for (int j = 0; j < w; ++j) {
                          char c = row[j];
                          if (c == 'O' && mrow[j] == 0) {
                              row[j] = 'X';
                          }
                      }
                  }
              }
          }





          評論

          # re: 包圍的區域  回復  更多評論   

          2013-04-22 10:43 by cintana
          貌似太復雜了,為啥不直接掃描邊上的‘o'呢,一下就解決了。

          # re: 包圍的區域  回復  更多評論   

          2013-04-22 18:05 by 小明
          @cintana

          謝謝,確實,我想復雜了
          主站蜘蛛池模板: 富裕县| 新丰县| 龙川县| 八宿县| 芒康县| 桂阳县| 中江县| 仁化县| 新田县| 资讯 | 霍林郭勒市| 鹿泉市| 拉萨市| 潼南县| 德阳市| 西安市| 民乐县| 汾西县| 元江| 洛隆县| 凌云县| 明光市| 托克托县| 泽州县| 和龙市| 故城县| 忻州市| 前郭尔| 六盘水市| 平顶山市| 长沙市| 招远市| 静安区| 玉环县| 太谷县| 东阳市| 阳朔县| 江达县| 洛隆县| 广元市| 个旧市|