classUnionFind { public: vector<int> parent; vector<int> size; int n; int setCount; public: UnionFind(int _n): n(_n), setCount(_n), parent(_n), size(_n, 1) { iota(parent.begin(), parent.end(), 0); } intfindset(int x){ return parent[x] == x ? x : parent[x] = findset(parent[x]); } voidunite(int x, int y){ if (size[x] < size[y]) { swap(x, y); } parent[y] = x; size[x] += size[y]; --setCount; } boolfindAndUnite(int x, int y){ int parentX = findset(x); int parentY = findset(y); if (parentX != parentY) { unite(parentX, parentY); returntrue; } returnfalse; } };
classSolution { public: boolcontainsCycle(vector<vector<char>>& grid){ int m = grid.size(); int n = grid[0].size(); UnionFind uf(m * n); for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (i > 0 && grid[i][j] == grid[i - 1][j]) { if (!uf.findAndUnite(i * n + j, (i - 1) * n + j)) { returntrue; } } if (j > 0 && grid[i][j] == grid[i][j - 1]) { if (!uf.findAndUnite(i * n + j, i * n + j - 1)) { returntrue; } } } } returnfalse; } };
classUnionFind: def__init__(self, n: int): self.n = n self.setCount = n self.parent = list(range(n)) self.size = [1] * n deffindset(self, x: int) -> int: if self.parent[x] == x: return x self.parent[x] = self.findset(self.parent[x]) return self.parent[x] defunite(self, x: int, y: int): if self.size[x] < self.size[y]: x, y = y, x self.parent[y] = x self.size[x] += self.size[y] self.setCount -= 1 deffindAndUnite(self, x: int, y: int) -> bool: parentX, parentY = self.findset(x), self.findset(y) if parentX != parentY: self.unite(parentX, parentY) returnTrue returnFalse
classSolution: defcontainsCycle(self, grid: List[List[str]]) -> bool: m, n = len(grid), len(grid[0]) uf = UnionFind(m * n) for i inrange(m): for j inrange(n): if i > 0and grid[i][j] == grid[i - 1][j]: ifnot uf.findAndUnite(i * n + j, (i - 1) * n + j): returnTrue if j > 0and grid[i][j] == grid[i][j - 1]: ifnot uf.findAndUnite(i * n + j, i * n + j - 1): returnTrue returnFalse
复杂度分析
时间复杂度:O(mn \cdot \alpha(mn))。上述代码中的并查集使用了路径压缩(path compression)以及按秩合并(union by size/rank)优化,单次合并操作的均摊时间复杂度为 \alpha(mn)。每一个位置最多进行两次合并操作,因此总时间复杂度为 O(mn \cdot \alpha(mn))。