class Solution {
public:
vector<vector<int>> matrixRankTransform(vector<vector<int>>& matrix) {
}
};
1632. 矩阵转换后的秩
给你一个 m x n
的矩阵 matrix
,请你返回一个新的矩阵 answer
,其中 answer[row][col]
是 matrix[row][col]
的秩。
每个元素的 秩 是一个整数,表示这个元素相对于其他元素的大小关系,它按照如下规则计算:
p
和 q
在 同一行 或者 同一列 ,那么:
p < q
,那么 rank(p) < rank(q)
p == q
,那么 rank(p) == rank(q)
p > q
,那么 rank(p) > rank(q)
题目保证按照上面规则 answer
数组是唯一的。
示例 1:
输入:matrix = [[1,2],[3,4]] 输出:[[1,2],[2,3]] 解释: matrix[0][0] 的秩为 1 ,因为它是所在行和列的最小整数。 matrix[0][1] 的秩为 2 ,因为 matrix[0][1] > matrix[0][0] 且 matrix[0][0] 的秩为 1 。 matrix[1][0] 的秩为 2 ,因为 matrix[1][0] > matrix[0][0] 且 matrix[0][0] 的秩为 1 。 matrix[1][1] 的秩为 3 ,因为 matrix[1][1] > matrix[0][1], matrix[1][1] > matrix[1][0] 且 matrix[0][1] 和 matrix[1][0] 的秩都为 2 。
示例 2:
输入:matrix = [[7,7],[7,7]] 输出:[[1,1],[1,1]]
示例 3:
输入:matrix = [[20,-21,14],[-19,4,19],[22,-47,24],[-19,4,19]] 输出:[[4,2,3],[1,3,4],[5,1,6],[1,3,4]]
示例 4:
输入:matrix = [[7,3,6],[1,4,5],[9,8,2]] 输出:[[5,1,4],[1,2,3],[6,3,1]]
提示:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 500
-109 <= matrix[row][col] <= 109
原站题解
python3 解法, 执行用时: 748 ms, 内存消耗: 63.5 MB, 提交时间: 2023-01-25 09:25:31
class Solution: def matrixRankTransform(self, matrix: List[List[int]]) -> List[List[int]]: LIM = 512 R, C = len(matrix), len(matrix[0]) res = [[0]*C for _ in range(R)] countR, countC = [0]*R, [0]*C # 按元素大小分别存储元素坐标 ls = collections.defaultdict(list) for r, row in enumerate(matrix): for c, val in enumerate(row): ls[val].append((r, c)) # 并查集用于合并行或列相同的元素 union = list(range(LIM*2)) def find(i): if union[i] == i: return i union[i] = find(union[i]) return union[i] # 按val从小到大遍历 pool = collections.defaultdict(list) for val in sorted(ls.keys()): # 用并查集合并行和列相同的元素并分组 for r, c in ls[val]: union[find(r)] = find(c+LIM) pool.clear() for r, c in ls[val]: pool[find(r)].append((r, c)) # 行和列相同的元素,共享相同的rank for group in pool.values(): rank = max(max((countR[r], countC[c])) for r, c in group) + 1 for r, c in group: countR[r] = countC[c] = res[r][c] = rank # 重置并查集 union[r] = r union[c+LIM] = c+LIM return res
java 解法, 执行用时: 182 ms, 内存消耗: 74.1 MB, 提交时间: 2023-01-25 09:24:58
class Solution { public int[][] matrixRankTransform(int[][] matrix) { int m = matrix.length, n = matrix[0].length; UnionFind uf = new UnionFind(m, n); for (int i = 0; i < m; i++) { Map<Integer, List<int[]>> num2indexList = new HashMap<Integer, List<int[]>>(); for (int j = 0; j < n; j++) { int num = matrix[i][j]; num2indexList.putIfAbsent(num, new ArrayList<int[]>()); num2indexList.get(num).add(new int[]{i, j}); } for (List<int[]> indexList : num2indexList.values()) { int[] arr1 = indexList.get(0); int i1 = arr1[0], j1 = arr1[1]; for (int k = 1; k < indexList.size(); k++) { int[] arr2 = indexList.get(k); int i2 = arr2[0], j2 = arr2[1]; uf.union(i1, j1, i2, j2); } } } for (int j = 0; j < n; j++) { Map<Integer, List<int[]>> num2indexList = new HashMap<Integer, List<int[]>>(); for (int i = 0; i < m; i++) { int num = matrix[i][j]; num2indexList.putIfAbsent(num, new ArrayList<int[]>()); num2indexList.get(num).add(new int[]{i, j}); } for (List<int[]> indexList : num2indexList.values()) { int[] arr1 = indexList.get(0); int i1 = arr1[0], j1 = arr1[1]; for (int k = 1; k < indexList.size(); k++) { int[] arr2 = indexList.get(k); int i2 = arr2[0], j2 = arr2[1]; uf.union(i1, j1, i2, j2); } } } int[][] degree = new int[m][n]; Map<Integer, List<int[]>> adj = new HashMap<Integer, List<int[]>>(); for (int i = 0; i < m; i++) { Map<Integer, int[]> num2index = new HashMap<Integer, int[]>(); for (int j = 0; j < n; j++) { int num = matrix[i][j]; num2index.put(num, new int[]{i, j}); } List<Integer> sortedArray = new ArrayList<Integer>(num2index.keySet()); Collections.sort(sortedArray); for (int k = 1; k < sortedArray.size(); k++) { int[] prev = num2index.get(sortedArray.get(k - 1)); int[] curr = num2index.get(sortedArray.get(k)); int i1 = prev[0], j1 = prev[1], i2 = curr[0], j2 = curr[1]; int[] root1 = uf.find(i1, j1); int[] root2 = uf.find(i2, j2); int ri1 = root1[0], rj1 = root1[1], ri2 = root2[0], rj2 = root2[1]; degree[ri2][rj2]++; adj.putIfAbsent(ri1 * n + rj1, new ArrayList<int[]>()); adj.get(ri1 * n + rj1).add(new int[]{ri2, rj2}); } } for (int j = 0; j < n; j++) { Map<Integer, int[]> num2index = new HashMap<Integer, int[]>(); for (int i = 0; i < m; i++) { int num = matrix[i][j]; num2index.put(num, new int[]{i, j}); } List<Integer> sortedArray = new ArrayList<Integer>(num2index.keySet()); Collections.sort(sortedArray); for (int k = 1; k < sortedArray.size(); k++) { int[] prev = num2index.get(sortedArray.get(k - 1)); int[] curr = num2index.get(sortedArray.get(k)); int i1 = prev[0], j1 = prev[1], i2 = curr[0], j2 = curr[1]; int[] root1 = uf.find(i1, j1); int[] root2 = uf.find(i2, j2); int ri1 = root1[0], rj1 = root1[1], ri2 = root2[0], rj2 = root2[1]; degree[ri2][rj2]++; adj.putIfAbsent(ri1 * n + rj1, new ArrayList<int[]>()); adj.get(ri1 * n + rj1).add(new int[]{ri2, rj2}); } } Set<Integer> rootSet = new HashSet<Integer>(); int[][] ranks = new int[m][n]; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { int[] rootArr = uf.find(i, j); int ri = rootArr[0], rj = rootArr[1]; rootSet.add(ri * n + rj); ranks[ri][rj] = 1; } } Queue<int[]> queue = new ArrayDeque<int[]>(); for (int val : rootSet) { if (degree[val / n][val % n] == 0) { queue.offer(new int[]{val / n, val % n}); } } while (!queue.isEmpty()) { int[] arr = queue.poll(); int i = arr[0], j = arr[1]; for (int[] adjArr : adj.getOrDefault(i * n + j, new ArrayList<int[]>())) { int ui = adjArr[0], uj = adjArr[1]; degree[ui][uj]--; if (degree[ui][uj] == 0) { queue.offer(new int[]{ui, uj}); } ranks[ui][uj] = Math.max(ranks[ui][uj], ranks[i][j] + 1); } } int[][] res = new int[m][n]; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { int[] rootArr = uf.find(i, j); int ri = rootArr[0], rj = rootArr[1]; res[i][j] = ranks[ri][rj]; } } return res; } } class UnionFind { int m, n; int[][][] root; int[][] size; public UnionFind(int m, int n) { this.m = m; this.n = n; this.root = new int[m][n][2]; this.size = new int[m][n]; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { root[i][j][0] = i; root[i][j][1] = j; size[i][j] = 1; } } } public int[] find(int i, int j) { int[] rootArr = root[i][j]; int ri = rootArr[0], rj = rootArr[1]; if (ri == i && rj == j) { return rootArr; } return find(ri, rj); } public void union(int i1, int j1, int i2, int j2) { int[] rootArr1 = find(i1, j1); int[] rootArr2 = find(i2, j2); int ri1 = rootArr1[0], rj1 = rootArr1[1]; int ri2 = rootArr2[0], rj2 = rootArr2[1]; if (ri1 != ri2 || rj1 != rj2) { if (size[ri1][rj1] >= size[ri2][rj2]) { root[ri2][rj2][0] = ri1; root[ri2][rj2][1] = rj1; size[ri1][rj1] += size[ri2][rj2]; } else { root[ri1][rj1][0] = ri2; root[ri1][rj1][1] = rj2; size[ri2][rj2] += size[ri1][rj1]; } } } }
python3 解法, 执行用时: 3612 ms, 内存消耗: 60.7 MB, 提交时间: 2023-01-25 09:24:34
class Solution: def matrixRankTransform(self, matrix: List[List[int]]) -> List[List[int]]: m, n = len(matrix), len(matrix[0]) uf = UnionFind(m, n) for i, row in enumerate(matrix): num2indexList = defaultdict(list) for j, num in enumerate(row): num2indexList[num].append([i, j]) for indexList in num2indexList.values(): i1, j1 = indexList[0] for k in range(1, len(indexList)): i2, j2 = indexList[k] uf.union(i1, j1, i2, j2) for j in range(n): num2indexList = defaultdict(list) for i in range(m): num2indexList[matrix[i][j]].append([i, j]) for indexList in num2indexList.values(): i1, j1 = indexList[0] for k in range(1, len(indexList)): i2, j2 = indexList[k] uf.union(i1, j1, i2, j2) degree = Counter() adj = defaultdict(list) for i, row in enumerate(matrix): num2index = {} for j, num in enumerate(row): num2index[num] = (i, j) sortedArray = sorted(num2index.keys()) for k in range(1, len(sortedArray)): i1, j1 = num2index[sortedArray[k - 1]] i2, j2 = num2index[sortedArray[k]] ri1, rj1 = uf.find(i1, j1) ri2, rj2 = uf.find(i2, j2) degree[(ri2, rj2)] += 1 adj[(ri1, rj1)].append([ri2, rj2]) for j in range(n): num2index = {} for i in range(m): num = matrix[i][j] num2index[num] = (i, j) sortedArray = sorted(num2index.keys()) for k in range(1, len(sortedArray)): i1, j1 = num2index[sortedArray[k - 1]] i2, j2 = num2index[sortedArray[k]] ri1, rj1 = uf.find(i1, j1) ri2, rj2 = uf.find(i2, j2) degree[(ri2, rj2)] += 1 adj[(ri1, rj1)].append([ri2, rj2]) rootSet = set() ranks = {} for i in range(m): for j in range(n): ri, rj = uf.find(i, j) rootSet.add((ri, rj)) ranks[(ri, rj)] = 1 q = deque([[i, j] for i, j in rootSet if degree[(i, j)] == 0]) while q: i, j = q.popleft() for ui, uj in adj[(i, j)]: degree[(ui, uj)] -= 1 if degree[(ui, uj)] == 0: q.append([ui, uj]) ranks[(ui, uj)] = max(ranks[(ui, uj)], ranks[(i, j)] + 1) res = [[1] * n for _ in range(m)] for i in range(m): for j in range(n): ri, rj = uf.find(i, j) res[i][j] = ranks[(ri, rj)] return res class UnionFind: def __init__(self, m, n): self.m = m self.n = n self.root = [[[i, j] for j in range(n)] for i in range(m)] self.size = [[1] * n for _ in range(m)] def find(self, i, j): ri, rj = self.root[i][j] if [ri, rj] == [i, j]: return [i, j] self.root[i][j] = self.find(ri, rj) return self.root[i][j] def union(self, i1, j1, i2, j2): ri1, rj1 = self.find(i1, j1) ri2, rj2 = self.find(i2, j2) if [ri1, rj1] != [ri2, rj2]: if self.size[ri1][rj1] >= self.size[ri2][rj2]: self.root[ri2][rj2] = [ri1, rj1] self.size[ri1][rj1] += self.size[ri2][rj2] else: self.root[ri1][rj1] = [ri2, rj2] self.size[ri2][rj2] += self.size[ri1][rj1]