# Flood Fill

Leetcode #733. 图像渲染：有一幅以二维整数数组表示的图画，每一个整数表示该图画的像素值大小，数值在 0 到 65535 之间。给你一个坐标 (sr, sc) 表示图像渲染开始的像素值（行 ，列）和一个新的颜色值 newColor，让你重新上色这幅图像。为了完成上色工作，从初始坐标开始，记录初始坐标的上下左右四个方向上像素值与初始坐标相同的相连像素点，接着再记录这四个方向上符合条件的像素点与他们对应四个方向上像素值与初始坐标相同的相连像素点，……，重复该过程。将所有有记录的像素点的颜色值改为新的颜色值。最后返回经过上色渲染后的图像。

image = [[1,1,1],

[1,1,0],

[1,0,1]]
sr = 1, sc = 1, newColor = 2

[2,2,0],

[2,0,1]]

image 和 image[0] 的长度在范围 [1, 50] 内。

image[i][j] 和 newColor 表示的颜色值在范围 [0, 65535]内。

 1 class Solution:
2     def floodFill(self, image: List[List[int]], sr: int, sc: int, newColor: int) -> List[List[int]]:
3         if not image:
4             return []
5
6         m, n = len(image), len(image[0])
7         dx = [1, -1, 0, 0]
8         dy = [0, 0, 1, -1]
9         preColor = image[sr][sc]
10         visited = set()
11
12         def isValid(i, j):
13             nonlocal image, visited
14             if 0<=i<m and 0<=j<n and image[i][j] == preColor and (i, j) not in visited:
15                 return True
16             return False
17
18         def dfs(i, j):
19             nonlocal image, newColor, visited
20             if not isValid(i, j):
21                 return
22             image[i][j] = newColor
24             for k in range(4):
25                 dfs(i + dx[k], j + dy[k])
26
27         dfs(sr, sc)
28         return image
View Code

 1 class Solution:
2     def floodFill(self, image: List[List[int]], sr: int, sc: int, newColor: int) -> List[List[int]]:
3         if not image:
4             return []
5
6         m, n = len(image), len(image[0])
7         dx = [1, -1, 0, 0]
8         dy = [0, 0, 1, -1]
9         preColor = image[sr][sc]
10         visited = set()
11
12         def isValid(i, j):
13             nonlocal image, visited
14             if 0<=i<m and 0<=j<n and image[i][j] == preColor and (i, j) not in visited:
15                 return True
16             return False
17
18         def bfs(i, j):
19             nonlocal image, newColor, visited
20
21             image[i][j] = newColor  # sr, sc 一定要染
23
24             queue = []
25             queue.append((i, j))
26
27             while queue:
28                 cur_i, cur_j = queue.pop(0)
29                 for k in range(4):
30                     new_i, new_j = cur_i+dx[k], cur_j+dy[k]
31
32                     if isValid(new_i, new_j):   # 如果相邻的要染，就染然后记录，然后作为下一层的起始点
33                         image[new_i][new_j] = newColor
35                         queue.append((new_i, new_j))
36
37         bfs(sr, sc)
38         return image
View Code

Leetcode # 1034. 边框着色：给出一个二维整数网格 grid，网格中的每个值表示该位置处的网格块的颜色。只有当两个网格块的颜色相同，而且在四个方向中任意一个方向上相邻时，它们属于同一连通分量。连通分量的边界是指连通分量中的所有与不在分量中的正方形相邻（四个方向上）的所有正方形，或者在网格的边界上（第一行/列或最后一行/列）的所有正方形。给出位于 (r0, c0) 的网格块和颜色 color，使用指定颜色 color 为所给网格块的连通分量的边界进行着色，并返回最终的网格 grid 。

 1 class Solution:
2     def colorBorder(self, grid: List[List[int]], r0: int, c0: int, color: int) -> List[List[int]]:
3         if not grid:
4             return []
5
6         m, n = len(grid), len(grid[0])
7         dx = [1, -1, 0, 0]
8         dy = [0, 0, 1, -1]
9         preColor = grid[r0][c0]
10         visited = set()
11
12
13         def dfs(i, j):
14             nonlocal grid, color, visited
15             if not (0<=i<m and 0<=j<n):  # 如果越界，返回0，不计数
16                 return 0
17             if (i, j) in visited:
18                 return 1  # 是已经遍历过的点，说明和上一层递归函数中点相连，计数1
19             if grid[i][j] != preColor:
20                 return 0  # 碰到其他颜色，返回0，不计数
21
22             # 以上情况都不是，遍历这个点
24
25             surround = 0
26             for k in range(4):
27                 surround += dfs(i + dx[k], j + dy[k])
28             if surround < 4:
29                 grid[i][j] = color  # 如果四面都是连通分量，染色这个点
30
31             return 1  # 这个点是连通分量，返回1
32
33
34         dfs(r0, c0)
35         return grid
View Code

Leetcode #200. 岛计数问题：给定一个由 '1'（陆地）和 '0'（水）组成的的二维网格，计算岛屿的数量。一个岛被水包围，并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。

输入:
11000
11000
00100
00011

if node ==1：

count ++; 将node附近陆地节点赋0

else:

continue

dfs 实现，递归自然的提供栈

 1 class Solution:
2     def numIslands(self, grid: List[List[str]]) -> int:
3         if not grid or not grid[0]:
4             return 0
5         self.dx = [-1, 1, 0, 0]
6         self.dy = [0, 0, -1, 1]  # 便于向四周扩散，先定义好(dx, dy)，左、右、下、上
7
8         self.max_x, self.max_y = len(grid), len(grid[0])  # 两个边界
9
10         self.grid = grid  # 便于传参
11         self.visited = set()   # 不污染原数组，用一个set做遍历标记
12
13         res = []
14         for i in range(self.max_x):  # 遍历所有节点，如果需要扩散染色就append 1，否则append 0
15             for j in range(self.max_y):
16                 res.append(self.floodfill_dfs(i,j))
17
18         return sum(res)  # sum后即为所求
19
20     def floodfill_dfs(self, x, y):
21         if not self.is_valid(x, y):  # 如果(x, y)不是需要扩散染色的陆地，直接返回0
22             return 0
24         for k in range(4):  # 左、右、下、上4个方向扩展遍历
25             self.floodfill_dfs(x + self.dx[k], y + self.dy[k])
26         return 1
27
28     def is_valid(self, x, y):
29         """判断(x, y)是否为需要扩散染色的陆地"""
30         if x < 0 or x >= self.max_x or y < 0 or y >= self.max_y:  # 越界的位置全是水
31             return False
32         if self.grid[x][y] == '0' or ((x, y) in self.visited):  # ‘0’ node 和 已经染色过的‘1’ node，都不需要染色，不破坏原数组grid
33             return False
34         return True
View Code

bfs实现，利用队列

 1 import collections
2 class Solution:
3     def numIslands(self, grid: List[List[str]]) -> int:
4         if not grid or not grid[0]:
5             return 0
6         self.dx = [-1, 1, 0, 0]
7         self.dy = [0, 0, -1, 1]  # 便于向四周扩散，先定义好(dx, dy)，左、右、下、上
8
9         self.max_x, self.max_y = len(grid), len(grid[0])  # 两个边界
10
11         self.grid = grid  # 便于传参
12         self.visited = set()   # 不污染原数组，用一个set做遍历标记
13
14         res = []
15         for i in range(self.max_x):  # 遍历所有节点，如果需要扩散染色就append 1，否则append 0
16             for j in range(self.max_y):
17                 res.append(self.floodfill_bfs(i,j))
18
19         return sum(res)  # sum后即为所求
20
21     def floodfill_bfs(self, x, y):
22         if not self.is_valid(x, y):  # 如果(x, y)不是需要扩散染色的陆地，直接返回0
23             return 0
24
26         queue = collections.deque()  # bfs用队列实现
27         queue.append((x,y))  # 先入队遍历的起始点
28
29         while queue:
30             cur_x, cur_y = queue.popleft()
31             for k in range(4):  # 所有和当前pop出来的节点相邻的点都要染色(前提是如果需要的话)
32                 new_x, new_y = cur_x+self.dx[k], cur_y+self.dy[k]
33                 if self.is_valid(new_x, new_y):
34                     self.visited.add((new_x, new_y))  # 相当于染色(new_x, new_y)
35                     queue.append((new_x, new_y))  # 相邻节点入队
36         return 1
37
38     def is_valid(self, x, y):
39         """判断(x, y)是否为需要扩散染色的陆地"""
40         if x < 0 or x >= self.max_x or y < 0 or y >= self.max_y:  # 越界的位置全是水
41             return False
42         if self.grid[x][y] == '0' or ((x, y) in self.visited):  # ‘0’ node 和 已经染色过的‘1’ node，都不需要染色，不破坏原数组grid
43             return False
44         return True
View Code

posted @ 2019-08-23 16:23  王朝君BITer  阅读(...)  评论(... 编辑 收藏