1. 程式人生 > 實用技巧 >LeetCode 733. 影象渲染 | Python

LeetCode 733. 影象渲染 | Python

733. 影象渲染


題目來源:力扣(LeetCode)https://leetcode-cn.com/problems/flood-fill

題目


有一幅以二維整數陣列表示的圖畫,每一個整數表示該圖畫的畫素值大小,數值在 0 到 65535 之間。

給你一個座標 (sr, sc) 表示影象渲染開始的畫素值(行 ,列)和一個新的顏色值 newColor,讓你重新上色這幅影象。

為了完成上色工作,從初始座標開始,記錄初始座標的上下左右四個方向上畫素值與初始座標相同的相連畫素點,接著再記錄這四個方向上符合條件的畫素點與他們對應四個方向上畫素值與初始座標相同的相連畫素點,……,重複該過程。將所有有記錄的畫素點的顏色值改為新的顏色值。

最後返回經過上色渲染後的影象。

示例 1:

輸入:
image = [[1,1,1],[1,1,0],[1,0,1]]
sr = 1, sc = 1, newColor = 2
輸出: [[2,2,2],[2,2,0],[2,0,1]]
解析:
在影象的正中間,(座標(sr,sc)=(1,1)),
在路徑上所有符合條件的畫素點的顏色都被更改成2。
注意,右下角的畫素沒有更改為2,
因為它不是在上下左右四個方向上與初始點相連的畫素點。

注意:

  • image 和 image[0] 的長度在範圍 [1, 50] 內。
  • 給出的初始點將滿足 0 <= sr < image.length 和 0 <= sc < image[0].length。
  • image[i][j] 和 newColor 表示的顏色值在範圍 [0, 65535]內。

解題思路


思路:DFS、BFS

先審題,題目要求是將某些符合條件的座標點進行重新上色。這裡這些座標點符合的定義為:直接或間接相鄰的與起始座標點顏色相同的部分。

在題目中,明確說了從給定的初始座標開始,往座標點四個方位進行擴散,標記與初始座標點顏色相同的座標,然後以這些標記的點繼續擴散,重複直至結束,將所有標記的點都重新上色。

那麼,我們這裡採用深度優先搜尋和廣度優先搜尋的形式來解決這個問題。

深度優先搜尋(DFS)

首先,先看深度優先搜尋如何處理。具體的做法如下:

  • 首先從給定的初始座標點開始向四個方位擴散,進行遍歷;
  • 每搜尋一個座標,確定是否與初始座標點顏色相同。如果相同,那麼重新上色,防止重新搜尋陷入死迴圈;如果不同,不處理。
  • 重複直至所有符合條件的點都重新上色,返回重新上色後的影象。

這裡有個需要注意的地方,進行擴散的時候,按照上面的做法,會將初始座標點進行重新上色。這個時候顏色的變化會影響後續。所以開始前用一個遍歷儲存初始座標點的顏色。
還有,給定的初始座標點顏色,可能與新給定的顏色相同,這樣直接呼叫會先入死迴圈。這也是測試用例沒通過注意到的。┑( ̄Д  ̄)┍

具體的程式碼見【程式碼實現 # 深度優先搜尋】

廣度優先搜尋(BFS)

在這裡,我們同樣可以使用廣度優先搜尋的思路來解決這個問題。下面看使用此方法的思路:

  • 宣告輔助佇列,從初始座標點開始,先將初始座標點入隊;
  • 出隊,開始搜尋,當遇到與初始座標點顏色相同的點時,入隊,同時將重新上色;
  • 迴圈直至佇列為空,返回重新上色後的影象。

同樣注意初始座標點顏色可能會被覆蓋的問題。

具體的程式碼見【程式碼實現 # 廣度優先搜尋】

程式碼實現


# 深度優先搜尋
class Solution:
    def floodFill(self, image: List[List[int]], sr: int, sc: int, newColor: int) -> List[List[int]]:
        # 先儲存初始座標點顏色
        init_color = image[sr][sc]
        # 邊界
        m = len(image)
        n = len(image[0])
        # 四個方位
        directions = [(0, 1), (0, -1), (-1, 0),(1, 0)]

        def dfs(x, y):
            """進行深度優先搜尋
            Args:
                x: 畫素值(行)
                y: 畫素值(列)
            """
            if image[x][y] == init_color:
                # 如果遇到與初始座標點顏色相同的點,重新上色,開始擴散
                image[x][y] = newColor
                for dx, dy in directions:
                    nx = x + dx
                    ny = y + dy
                    # 限定邊界
                    if 0 <= nx < m and 0 <= ny < n and image[nx][ny] == init_color:
                        dfs(nx, ny)

        # 注意:
        # 有可能一開始給定的初始座標點的顏色與後面給定的新顏色是相同的
        # 直接呼叫會先入死迴圈,直至超出遞迴深度
        if init_color != newColor:
            dfs(sr, sc)

        return image

# 廣度優先搜尋
class Solution:
    def floodFill(self, image: List[List[int]], sr: int, sc: int, newColor: int) -> List[List[int]]:
        # 先儲存初始座標點顏色
        init_color = image[sr][sc]
        # 邊界
        m = len(image)
        n = len(image[0])
        # 四個方位
        directions = [(0, 1), (0, -1), (-1, 0),(1, 0)]

        def bfs(sr, sc):
            """進行深度優先搜尋
            Args:
                sr: 畫素值(行)
                sc: 畫素值(列)
            """
            # 宣告輔助佇列
            from collections import deque
            queue = deque()
            # 入隊
            queue.append([sr, sc])
            # 重新上色
            image[sr][sc] = newColor
            # 出隊,開始搜尋
            while queue:
                x, y = queue.popleft()
                for dx, dy in directions:
                    nx = x + dx
                    ny = y + dy
                    if 0 <= nx < m and 0 <= ny < n and image[nx][ny] == init_color:
                        # 當遇到與初始座標點顏色相同的,入隊,並重新上色
                        queue.append([nx, ny])
                        image[nx][ny] = newColor

        if init_color != newColor:
            bfs(sr, sc)

        return image

實現結果


歡迎關注


公眾號 【書所集錄