1. 程式人生 > >Surrounded Regions -- LeetCode

Surrounded Regions -- LeetCode

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

                原題連結:  http://oj.leetcode.com/problems/surrounded-regions/  
這個題目用到的方法是圖形學中的一個常用方法:
Flood fill演算法
,其實就是從一個點出發對周圍區域進行目標顏色的填充。背後的思想就是把一個矩陣看成一個圖的結構,每個點看成結點,而邊則是他上下左右的相鄰點,然後進行一次廣度或者深度優先搜尋。
接下來我們看看這個題如何用 Flood fill演算法 來解決。首先根據題目要求,邊緣上的'O'是不需要填充的,所以我們的辦法是對上下左右邊緣做 Flood fill演算法 ,把所有邊緣上的'O'都替換成另一個字元,比如'#'。接下來我們知道除去被我們換成'#'的那些頂點,剩下的所有'O'都應該被替換成'X',而'#'那些最終應該是還原成'O',如此我們可以做最後一次遍歷,然後做相應的字元替換就可以了。複雜度分析上,我們先對邊緣做
Flood fill演算法 ,因為只有是'O'才會進行,而且會被替換成'#',所以每個結點改變次數不會超過一次,因而是O(m*n)的複雜度,最後一次遍歷同樣是O(m*n),所以總的時間複雜度是O(m*n)。空間上就是遞迴棧(深度優先搜尋)或者是佇列(廣度優先搜尋)的空間,同時存在的空間佔用不會超過O(m+n)(以廣度優先搜尋為例,每次佇列中的結點雖然會往四個方向拓展,但是事實上這些結點會有很多重複,假設從中點出發,可以想象最大的擴充套件不會超過一個菱形,也就是n/2*2+m/2*2=m+n,所以演算法的空間複雜度是O(m+n))。程式碼如下:
public void solve
(char[][] board)
{    if(board==null || board.length<=1 || board[0].length<=1)        return;    for(int i=0;i<board[0].length;i++)    {        fill(board,0,i);        fill(board,board.length-1,i);    }    for(int i=0;i<board.length;i++)    {        fill(board,i,0);        fill(board,i,board[0].length-1);    }    for(int i=0;i<board.length;i++)    {        for(int j=0;j<board[0].length;j++)        {            if(board[i][j]=='O')                board[i][j]='X';            else if(board[i][j]=='#')                board[i][j]='O';                        }    }}private void fill(char[][] board, int i, int j){    if(board[i][j]!='O')        return;    board[i][j] = '#';    LinkedList<Integer> queue = new LinkedList<Integer>();    int code = i*board[0].length+j;    queue.offer(code);    while(!queue.isEmpty())    {        code = queue.poll();        int row = code/board[0].length;        int col = code%board[0].length;        if(row>0 && board[row-1][col]=='O')        {            queue.offer((row-1)*board[0].length+col);            board[row-1][col]='#';        }        if(row<board.length-1 && board[row+1][col]=='O')        {            queue.offer((row+1)*board[0].length+col);            board[row+1][col]='#';        }        if(col>0 && board[row][col-1]=='O')        {            queue.offer(row*board[0].length+col-1);            board[row][col-1]='#';        }        if(col<board[0].length-1 && board[row][col+1]=='O')        {            queue.offer(row*board[0].length+col+1);            board[row][col+1]='#';        }                }}
可以看到上面程式碼用的是廣度優先搜尋,用一個佇列來維護,當然也可以用深度優先搜尋,但是如果使用遞迴,會發現LeetCode過不了,這是因為在圖形中通常圖片(或者說這裡的矩陣)一般會很大,遞迴很容易導致棧溢位,所以即使要用深度優先搜尋,也最好使用非遞迴的實現方式哈。
           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述