https://leetcode.com/problems/rank-transform-of-a-matrix/
对并查集的灵活运用,一个比较典型的变种!
个人解答
class Solution:def matrixRankTransform(self, mat: List[List[int]]) -> List[List[int]]:m, n = len(mat), len(mat[0])# get pos with same valuemp = collections.defaultdict(list)for i in range(m):for j in range(n):mp[mat[i][j]].append((i, j))# union-find opsdef set_find(st, x):if st[x] < 0:return xst[x] = set_find(st, st[x])return st[x]def set_union(st, x, y):rx = set_find(st, x)ry = set_find(st, y)if rx == ry:returnif st[rx] < st[ry]:st[rx] += st[ry]st[ry] = rxelse:st[ry] += st[rx]st[rx] = ry# record rank of rows and colsrank = [0] * (m + n)res = [[0] * n for _ in range(m)]for v in sorted(mp.keys()):# union-find set, put rows and cols together for convinientst = [-1] * (m + n)# deep copy, prevent inconsistant updaterank1 = rank[:]for x, y in mp[v]:# put pos with same x/y together, and calculate min valid rankrx = set_find(st, x)ry = set_find(st, y + m)r = max(rank1[rx], rank1[ry])rank1[rx] = rank1[ry] = max(rank1[rx], rank1[ry], r)set_union(st, rx, ry)# update rankfor x, y in mp[v]:res[x][y] = rank[x] = rank[y + m] = rank1[set_find(st, x)] + 1return res
题目分析
其实题目并不是那么直截了当地告诉你要用并查集。
题目大致有两个关键点:
- 贪心策略:每次找出最小的值,可以保证所赋的rank不受后边的值影响
- 对于相同值得处理:这是比较容易忽略的,考虑到同时满足相同的值需要有相同的rank,以及不同位置可能有不同的最小rank,需要找到满足所有位置的最小rank。而找到这些相互影响的位置是其中的关键。
这是一个很经典的问题了,找出相互关联的位置,可以BFS/DFS,类似找出连通子图数量。当然,这个问题最合理的方式还是并查集。
由于涉及行列的二维,构造集合时,可以考虑建一个m+n长度的数组,这样就可以在一个数组里表示所有的两个维度的信息了,后续查找的时候也更加方便,这是一个很有用的小技巧。
有了这个并查集的结构,其它的也就顺利成章了,找到所有相互关联的位置,确定他们的最小合理rank即可。
这道题仔细分析并不是很难,但是如何优雅而快速的写出来不是那么容易,因此,有必要记下来学习学习。
