小明思考

          Just a software engineer
          posts - 124, comments - 36, trackbacks - 0, articles - 0
            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理
          問(wèn)題給定一個(gè)2D的棋盤(pán),含有‘X'和’O',找到所有被‘X'包圍的’O',然后把該區(qū)域的‘O’都變成'X'。

          例子-輸入:
          X X X X
          X O O X
          X X O X
          X O X X

          應(yīng)該輸出:

          X X X X
          X X X X
          X X X X
          X O X X

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

          分析:
          為了提高效率,我使用了一個(gè)mark數(shù)組來(lái)記錄所有訪問(wèn)過(guò)的‘O'點(diǎn),避免重復(fù)檢查,同時(shí)要避免死循環(huán)。
          每個(gè)點(diǎn)有四種狀態(tài),未檢測(cè)(0),正在檢測(cè)(-1),包圍的點(diǎn)(1),沒(méi)有被包圍的點(diǎn)(2)。
          另外,為了對(duì)付很大的棋盤(pán),避免使用遞歸而造成堆棧溢出,使用了一個(gè)檢測(cè)隊(duì)列。

          代碼如下:

          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====
          改進(jìn)了一下,從邊開(kāi)始掃描,找到所有邊上白字相鄰的節(jié)點(diǎn)即可解決問(wèn)題。代碼如下:

          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';
                          }
                      }
                  }
              }
          }





          評(píng)論

          # re: 包圍的區(qū)域  回復(fù)  更多評(píng)論   

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

          # re: 包圍的區(qū)域  回復(fù)  更多評(píng)論   

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

          謝謝,確實(shí),我想復(fù)雜了
          主站蜘蛛池模板: 府谷县| 郸城县| 淮滨县| 兴国县| 平遥县| 修水县| 大理市| 大厂| 瑞安市| 晴隆县| 西宁市| 黄浦区| 磐石市| 寿宁县| 邵阳市| 鹤庆县| 马山县| 台山市| 修武县| 遂溪县| 东至县| 凉城县| 娱乐| 平武县| 修武县| 西青区| 余庆县| 依安县| 牟定县| 盘山县| 镇远县| 承德市| 资溪县| 大姚县| 五峰| 盘山县| 仁怀市| 唐山市| 阳江市| 泽普县| 河北省|