題目
紀錄一下一開始的思路,檢討錯誤,再整理最後的答案。一開始的想法:
- 這應該可以分解成最小可重複動作,用遞迴解看看
- 覺得可以用原本的 method 當遞迴函式,把
image,color照樣傳入,sr,sc為該點的座標 - 最小可重複動作:從當下這點擴散到周圍四個點
1 | def floodFill(self, image: List[List[int]], sr: int, sc: int, color: int) -> List[List[int]]: |
結果發生 index out of bound error (舉例,當 sr == m - 1 時,再用 image[sr + 1] 就會遇到)
檢討:
會用到
image[sr + 1]是為了要取到鄰近的顏色來判斷是不是應該去 flood,而那些判斷只是為了決定是否要執行遞迴呼叫 => 判斷是否該執行遞迴呼叫應該直接在該遞迴函式的 base case 裡做判斷- 不去取顏色自然就不會遇到這個錯誤
- 改成在 base case 的判斷
我這個點的顏色是不是跟起點的顏色一樣
中間這段沒必要,此情境已包含於那些遞迴呼叫裡
1
2
3if self_color not in (l_color, r_color, u_color, d_color):
image[sr][sc] = color
return image可以把題目的
color參數名改為new_color,增加可讀性可以另外用一個 inner function 來當遞迴函式,因為實際會傳不一樣參數的只有座標,另兩個其實可以不用傳入,另外用一個 inner function 可以讓程式更簡潔易讀
1 | def floodFill(self, image: List[List[int]], sr: int, sc: int, new_color: int) -> List[List[int]]: |
- 記得要先把起點的顏色記到變數裡,而不是在 base case 的判斷裡直接用
image[sr][sc]來取,因為起點的顏色在經過第一次flood呼叫後就變了 - base case 裡這個判斷
image[row][col] == new_color,它主要是在看假如這個點已經 flood 過了,就直接return,但還有一種情形:沒 flood 過,這個點本來就是 new_color。假如是這種情況,又再細分為以下兩個情形:ori_color != new_color: 假如是這種情況,在前面的image[row][col] != ori_color就會滿足而return了ori_color == new_color: 此時也應該return,因為假如是這樣,那本來整個 image 就不會因為floodFill而變
上面的遞迴解法是屬於 DFS (Depth-First Search),假如用 BFS (Breadth-First Search) 來解呢?
假如已經用 DFS 解過了,那 BFS 應該可以依循同樣的思考邏輯很快寫出來,只需調整一下架構:
- 先過濾掉不需繼續做的情況
- 準備一個 stack,放入起始情況的條件
- 只要 stack 裡有東西,就做最小可重複動作
終止條件對應到上面的 base case,要繼續檢查的部分對應到上面的 recursive case
1 | def floodFill(self, image: List[List[int]], sr: int, sc: int, new_color: int) -> List[List[int]]: |