leetcode1559. 二维网格图中探测环
给你一个二维字符网格数组 grid
,大小为 m x n
,你需要检查 grid
中是否存在 相同值 形成的环。
一个环是一条开始和结束于同一个格子的长度 大于等于 4 的路径。对于一个给定的格子,你可以移动到它上、下、左、右四个方向相邻的格子之一,可以移动的前提是这两个格子有 相同的值 。
同时,你也不能回到上一次移动时所在的格子。比方说,环 (1, 1) -> (1, 2) -> (1, 1)
是不合法的,因为从 (1, 2)
移动到 (1, 1)
回到了上一次移动时的格子。
如果 grid
中有相同值形成的环,请你返回 true
,否则返回 false
。
示例 1:
输入:grid = [["a","a","a","a"],["a","b","b","a"],["a","b","b","a"],["a","a","a","a"]]
输出:true
解释:如下图所示,有 2 个用不同颜色标出来的环:
示例 2:
输入:grid = [["c","c","c","a"],["c","d","c","c"],["c","c","e","c"],["f","c","c","c"]]
输出:true
解释:如下图所示,只有高亮所示的一个合法环:
示例 3:
输入:grid = [["a","b","b"],["b","z","b"],["b","b","a"]]
输出:false
提示:
m == grid.length
n == grid[i].length
1 <= m <= 500
1 <= n <= 500
grid
只包含小写英文字母。
方法:并查集
思路:
本题的做法有很多,常见的是DFS和BFS,这里介绍使用并查集的方法。
无论是哪种方法,我们都是将这个grid数组当作图来处理,即两个相邻的,且字母相同的点之间有一条无向路径。
对于并查集来说,如果两个点之间有路径,那么这两个点就应该进行合并。我们**对数组中的某个点,将它与上面和左面两个相邻的点进行比较,如果字母相同,则将两点相连。**之所以不选择对四个方向的相邻点进行合并,是因为如果对上下左右四个点进行比较,那么在遍历到下一个点的时候(比如该点右边的点),该点的左边点即为原来的点,导致重复;对于其他三个方向也构成重复,因此我们只选择两个方向的相邻点,这样每两个相邻点之间都只会处理一次。
下面我们考虑如何判断是环,对于某个点,我们与上面和左面的两个点进行处理,假设这两个中的某个点与该点字母相同,即需要合并,如果进行合并操作时候,发现这两个点的根节点相同,即已经在同一个连通分量了,那么就说明产生了环(因为刚开始每个点都是单独的根节点,通过不断的合并,这两个点都合并到了一个根节点下,再次遍历这个点,肯定产生了环)。
因此,我们构建长度为m * n的并查集,遍历数组中每个点,对它上面和左面两个相邻点进行操作,如果两者字母相等,且不再同一根节点,那么二者合并到一个根节点下;如果二者已经是同一个根节点了,说明遇到了环,直接返回True。遍历结束没有返回的话,返回False,说明没有环,详情见代码。
值得注意的是,二维数组中对应的点,在并查集中为一维数组,因此需要进行转换,对于点(i,j),它在并查集中的位置为i*n+j
。
代码:
Python3:
class UnionFind:
#初始化,一共n个节点的并查集
def __init__(self,n):
self.parent = [k for k in range(n)]
#查找某个元素的根节点
def find(self,index):
if self.parent[index] == index:
return index
#递归进行路径压缩
self.parent