# leetcode 130 被环绕的区域# 给定一个二维的矩阵,包含 'X' 和 'O'(字母 O)。找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。# 被围绕的区间不会存在于边界上,换句话说,任何边界上的 'O' 都不会被填充为 'X'。 任何不在边界上,或不与边界上的 'O' 相连的 'O' 最终都会被填充为 'X'。# 如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。# 找到被x包围的o不容易找,这时候就反其道而行之,找没有被x包围的o,然后将其先替换成为其他字母,然后最终遍历整个表,将符号变为o,o变为x# 解题思想:DFS and BFS"""
x x x x x x x x x x x x x x x x
x x o x ----> x x o x ----> x x o x ----> x x x x
x o x x x o x x x # x x x o x x
x o x x x # x x x # x x x o x x
"""# DFS解题defsolve(self, board):"""
:type board: List[List[str]]
:rtype: None Do not return anything, modify board in-place instead.
"""# 如果board是空的,则返回ifnot board:return# 计算数组的row和col
row =len(board)
col =len(board[0])# 如果row和col小于3,则不可能出现被包围的oif row <3or col <3:return board
# 深度优先遍历,首先,遍历第一行,最后一行,第一列以及最后一列,遇到x pass ,遇到 o 将 o 先写成 # 然后对这个地方朝向上下左右进行深度优先遍历,# 出界或者遇到 x 返回,遇到 o 将其改成 # ,然后递归的对这个 o 上下左右进行深度优先遍历,重复上述操作,直到没有复合要求的点defdfs(i,j):# 如果i和j越界或者是遇见了x则返回if i <0or j <0or i >= row or j >= col or board[i][j]=='x':return# 如果均不越界,以及遇见了‘o’,首先将其变为'#'
board[i][j]=='#'# 然后对其四个方向进行递归操作
dfs(i-1,j)
dfs(i+1,j)
dfs(i,j-1)
dfs(i,j+1)# 对第一列,最后一列进行查询for i inrange(row):
dfs(i,0)
dfs(i,col-1)# 对第一行,最后一行进行查询for i inrange(col):
dfs(0,i)
dfs(row-1,i)# 全部搜索完毕后,将board中的‘#’ 变为‘o’,o变为xfor i inrange(row):for j inrange(col):if board[i][j]=='o':
board[i][j]=='x'if board[i][j]=='#':
board[i][j]=='o'# BFS解题# BFS解题的主要思想:利用队列模拟bfs操作,其实主要的思想与上述的DFS类似defsolve(self, board):"""
:type board: List[List[str]]
:rtype: None Do not return anything, modify board in-place instead.
"""# 如果board是空的,则返回ifnot board:return# 计算board的row和col
row =len(board)
col =len(board[0])# 如果col和row小于3,则不可能出现被x包围的oif col <3or row <3:return board
# 广度优先遍历,defbfs(i,j):# 首先导入双端队列数据结构,方便与下面的操作from collections import deque
queue = deque()# 首先将传入的广度优先遍历的跟节点穿入到双端队列中
queue.appendleft((i,j))while queue:
i, j = queue.pop()# 判断i,j是否越界,或者说是board[i][j]是否为'o'if i <0or j <0or i > row-1or j > col-1or board[i][j]=='x':return# 否则,就修改board[i][j] = '#'
board[i][j]='#'# 将所有的邻接节点加入到双端队列中
queue.appendleft((i+1,j))
queue.appendleft((i-1,j))
queue.appendleft((i,j+1))
queue.appendleft((i,j-1))# 遍历第一行与最后一行for i inrange(col):
bfs(0,i)
bfs(row-1,i)# 遍历第一列与最后一列for i inrange(row):
bfs(i,0)
bfs(i,col-1)# 全部遍历完成之后,再修改其中的内容for i inrange(row):for j inrange(col):if board[i][j]=='o':
board[i][j]=='x'if board[i][j]=='#':
board[i][j]=='o'# Union解题# Union解题的主要思想:# 并查集的思想就是,同一个连通区域内的所有点的根节点是同一个。# 将每个点映射成一个数字。先假设每个点的根节点就是他们自己,然后我们以此输入连通的点对,# 然后将其中一个点的根节点赋成另一个节点的根节点,这样这两个点所在连通区域又相互连通了。# 并查集的基本操作# 1,find(int m):查找m的根节点
par ={}deffind(m):"""
:type m : int
:rtyoe :root
"""
par.setdefault(x,x)if par[x]!= x:
par[x]= find(par[x])return par[x]# 2,isConnected(int m,int n) 判断m,n两个点是否在同一个连通区域defisConnected(m,n):"""
:type m : int
:type n : int
:rtype : bool
"""return find(m)== find(n)# 3,union(int m, int n) 合并m,n两个点所在的连通区域defunion(m,n):"""
:type m : int
:type n : int
:rtype : None
"""
find(find(n))= find(m)defsolve(self, board):"""
:type board: List[List[str]]
:rtype: None Do not return anything, modify board in-place instead.
"""# f词典收录节点与该节点的父节点的映射
f ={}# 并查集的基本操作之一,查找点x的跟节点deffind(x):# setdefault() 返回的键如果不在字典中,会添加键(更新字典)
f.setdefault(x, x)# 寻找该节点的最终跟节点的操作,也相当于采用了递归的方法,知道找到最终的根节点if f[x]!= x:
f[x]= find(f[x])# 返回最终的x的根节点return f[x]# 并查集的基本操作之一,合并m,n两个节点所在的连通区域defunion(x, y):# 合并的思想是,先找的y的跟节点,然后将y的根节点的跟节点映射到x的跟节点上面去
f[find(y)]= find(x)# 如果board为空ifnot board ornot board[0]:return# 计算board的row和col
row =len(board)
col =len(board[0])# dummy代表不需要修改的'o'的根节点
dummy = row * col
# 对表中所有的元素进行遍历for i inrange(row):for j inrange(col):if board[i][j]=="O":# 如果找到了'o',并且其存在于边界上,则if i ==0or i == row -1or j ==0or j == col -1:
union(i * col + j, dummy)else:for x, y in[(-1,0),(1,0),(0,-1),(0,1)]:if board[i + x][j + y]=="O":
union(i * col + j,(i + x)* col +(j + y))for i inrange(row):for j inrange(col):if find(dummy)== find(i * col + j):
board[i][j]="O"else:
board[i][j]="X"# leetcode 200. 岛屿数量# 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。# 一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。classSolution(object):# 并查集解题:defnumIslands(self, grid):"""
:type grid: List[List[str]]
:rtype: int
"""
f ={}deffind(x):
f.setdefault(x, x)if f[x]!= x:
f[x]= find(f[x])return f[x]defunion(x, y):
f[find(x)]= find(y)ifnot grid:return0
row =len(grid)
col =len(grid[0])for i inrange(row):for j inrange(col):if grid[i][j]=="1":for x, y in[[-1,0],[0,-1]]:
tmp_i = i + x
tmp_j = j + y
if0<= tmp_i < row and0<= tmp_j < col and grid[tmp_i][tmp_j]=="1":
union(tmp_i * col + tmp_j, i * col + j)# print(f)
res =set()for i inrange(row):for j inrange(col):if grid[i][j]=="1":
res.add(find((i * col + j)))returnlen(res)# DFSdefnumIslands(self, grid):"""
:type grid: List[List[str]]
:rtype: int
"""ifnot grid:return0
row =len(grid)
col =len(grid[0])
cnt =0defdfs(i, j):
grid[i][j]="0"for x, y in[[-1,0],[1,0],[0,-1],[0,1]]:
tmp_i = i + x
tmp_j = j + y
if0<= tmp_i < row and0<= tmp_j < col and grid[tmp_i][tmp_j]=="1":
dfs(tmp_i, tmp_j)for i inrange(row):for j inrange(col):if grid[i][j]=="1":
dfs(i, j)
cnt +=1return cnt
# BFSdefnumIslands(self, grid):"""
:type grid: List[List[str]]
:rtype: int
"""from collections import deque
ifnot grid:return0
row =len(grid)
col =len(grid[0])
cnt =0defbfs(i, j):
queue = deque()
queue.appendleft((i, j))
grid[i][j]="0"while queue:
i, j = queue.pop()for x, y in[[-1,0],[1,0],[0,-1],[0,1]]:
tmp_i = i + x
tmp_j = j + y
if0<= tmp_i < row and0<= tmp_j < col and grid[tmp_i][tmp_j]=="1":
grid[tmp_i][tmp_j]="0"
queue.appendleft((tmp_i, tmp_j))for i inrange(row):for j inrange(col):if grid[i][j]=="1":
bfs(i, j)
cnt +=1return cnt
# leetcode 547. 朋友圈# 班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。classSolution(object):deffindCircleNum(self, M):"""
:type M: List[List[int]]
:rtype: int
"""
parent =[-1for _ inrange(len(M))]deffind(parent, i):if parent[i]==-1:return i
return find(parent, parent[i])defunion(parent, x, y):
xroot = find(parent, x)
yroot = find(parent, y)if xroot != yroot:
parent[xroot]= yroot
defunion_find(Matrix):for i inrange(len(Matrix)):for j inrange(len(Matrix)):if Matrix[i][j]==1and i != j:
union(parent, i, j)
count =0for i inrange(len(parent)):if parent[i]==-1:
count +=1return count
return union_find(M)# leetcode 1319 连通网络的操作次数"""
算法框架如下:
比较 n - 1 和 len(connections):
如果前者大于后者,那么一定无解,返回 -1;
如果前者小于等于后者,那么我们统计出图中的连通分量数 k,返回 k - 1。
统计图中连通分量数的方法有很多,我们介绍深度优先搜索和并查集两种方法。
"""classSolution(object):# DFSdefmakeConnected(self, n, connections):"""
:type n: int
:type connections: List[List[int]]
:rtype: int
"""iflen(connections)< n -1:return-1
edges ={x:list()for x inrange(n)}for c0, c1 in connections:
edges[c0].append(c1)
edges[c1].append(c0)
used =set()defdfs(u):
used.add(u)for v in edges[u]:if v notin used:
dfs(v)
part =0for i inrange(n):if i notin used:
part +=1
dfs(i)return part -1# 并查集defmakeConnected(self, n, connections):"""
:type n: int
:type connections: List[List[int]]
:rtype: int
"""iflen(connections)< n -1:return-1
fa =[x for x inrange(n)]deffindset(x):if x != fa[x]:
fa[x]= findset(fa[x])return fa[x]
part = n
for c0, c1 in connections:
p, q = findset(c0), findset(c1)if p != q:
part -=1
fa[p]= q
return part -1