FTPrep, 130 Surrounded Regions

来源:互联网 发布:java unix时间戳 时区 编辑:程序博客网 时间:2024/06/04 17:58

这道题还是蛮不错的,结合比较多的知识点,对我来说有几个新的点:

1, BFS的iterative方法。把所有的可以延伸的点都收集到一个queue里,从尾巴上加,头部poll,这让我想到了UBER实习第一面时,面试官说我自己实现了queue的结构,我现在想想确实在treelevel traversal 的题型中,也可以用queue来traversal,只要在每一层里,先知道queuesize,然后poll这么多次就正好把这一层的node给遍历完。对的!TODO  TODO.

2. 这里非常聪明的把 x 和 y encode了,相当于matrix.width 进制,保证了一一对应,不出现重复情况。

3. floodfill的方法非常直观且容易理解。其实就是这道题要调用的一个方法,在matrix的四周进行实现。

4. 看主方法里的步骤,就可以对整体的思路有很直接的了解了:a,对四周进行floodfill;b,再对matrics进行全局扫瞄,对+和 o进行判断。

我自己的一些对这道题的描述:

// 还要说下整体思路: 对周围的4条边进行floodfill的操作,把所有的O都设置成#,一种区别与内陆湖和陆地这两种的颜色/符号,就相当于海洋的水。

// 这样的话 在完成了floodfill之后,就要把内陆湖给填满,然后把海水还是还原成水。所以这道题的本质是什么?就是题目中给出所有的水都只有以各种表示形式。题目的问题是,要把淡水,即内陆湖,和咸水,及海洋水给分离开。分离开之后,可以对内陆湖进行填充,然后海洋的话,还是还原成海水。

问题抽象: 通过位置特点把所有水分成两种,对其实一种加一个特殊标记即可。完成了区分后,把原有的标记进行ops这里是替换。最后把特殊标记后的点都复原回来。

题目的整体思路是这样,技术难点在于,怎么根据位置去 标记不同的水域,BFS就是这样解决的。同时要知道BFS有两种实现方式:递归和迭代/通过queue来维护。

用迭代的方式实现BFS的代码:

class Solution {    public void solve(char[][] board) {        if(board.length==0 || board[0].length==0) return;        int height=board.length;        int width=board[0].length;        for(int i=0; i<height; i++){            floodFill(board, i, 0);            floodFill(board, i, width-1);        }        for(int j=1; j<width-1; j++){            floodFill(board, 0, j);            floodFill(board, height-1, j);        }        for(int i=0; i<height; i++){            for(int j=0; j<width; j++){                if(board[i][j]=='O') board[i][j]='X';                else if(board[i][j]=='+') board[i][j]='O';            }        }    }        private void floodFill(char[][] board, int row, int col){        if(board[row][col]!='O') return;        // board[row][col]=='O';        board[row][col]='+';        LinkedList<Integer> pointCodeQueue = new LinkedList<>();        int pointCode = row*board[0].length+ col;        pointCodeQueue.add(pointCode);        while(!pointCodeQueue.isEmpty()){            int polledPointCode =pointCodeQueue.poll();            int pointRow= polledPointCode/board[0].length;            int pointCol= polledPointCode%board[0].length;            if(pointRow>0 && board[pointRow-1][pointCol]=='O'){                   // >1 or >0 都可以,但是后者有一定重复。因为所有边界点都作为了起点。                // 等等,其实好像也不算重复,因为如果被改成*了,其实从这个起点开始的话就立马返回了。                board[pointRow-1][pointCol]='+';                pointCodeQueue.add(polledPointCode-board[0].length);            }            if(pointRow<board.length-1 && board[pointRow+1][pointCol]=='O'){                // pointRow<board.length-1 or -2 都可以,道理同上。                board[pointRow+1][pointCol]='+';                pointCodeQueue.add(polledPointCode+board[0].length);            }            if(pointCol>0 && board[pointRow][pointCol-1]=='O'){                board[pointRow][pointCol-1]='+';                pointCodeQueue.add(polledPointCode-1);            }            if(pointCol<board[0].length-1 && board[pointRow][pointCol+1]=='O'){                board[pointRow][pointCol+1]='+';                pointCodeQueue.add(polledPointCode+1);            }        }    }    }

用递归的方式实现BFS的代码:

// 用递归的方式实现flood fill 算法。class Solution {    public void solve(char[][] board) {        if (board.length == 0 || board[0].length == 0)return;if (board.length < 2 || board[0].length < 2)return;int m = board.length, n = board[0].length;//Any 'O' connected to a boundary can't be turned to 'X', so ...//Start from first and last column, turn 'O' to '*'.for (int i = 0; i < m; i++) {if (board[i][0] == 'O')boundaryDFS(board, i, 0);if (board[i][n-1] == 'O')boundaryDFS(board, i, n-1);}//Start from first and last row, turn 'O' to '*'for (int j = 0; j < n; j++) {if (board[0][j] == 'O')boundaryDFS(board, 0, j);if (board[m-1][j] == 'O')boundaryDFS(board, m-1, j);}//post-prcessing, turn 'O' to 'X', '*' back to 'O', keep 'X' intact.for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (board[i][j] == 'O')board[i][j] = 'X';else if (board[i][j] == '*')board[i][j] = 'O';}}}//Use DFS algo to turn internal however boundary-connected 'O' to '*';private void boundaryDFS(char[][] board, int i, int j) {if (i < 0 || i > board.length - 1 || j <0 || j > board[0].length - 1)return;if (board[i][j] == 'O')board[i][j] = '*';if (i > 1 && board[i-1][j] == 'O')boundaryDFS(board, i-1, j);if (i < board.length - 2 && board[i+1][j] == 'O')boundaryDFS(board, i+1, j);if (j > 1 && board[i][j-1] == 'O')boundaryDFS(board, i, j-1);if (j < board[i].length - 2 && board[i][j+1] == 'O' )boundaryDFS(board, i, j+1);}}

图片数据可以很大,所以递归的话很容易栈溢出 或者 超时。