# [LeetCode 1632. Rank Transform of a Matrix](https://leetcode.com/explore/challenge/card/august-leetcoding-challenge-2021/614/week-2-august-8th-august-14th/3874/) ### Daily challenge Aug 8, 2021 (HARD) >Given an `m x n matrix`, return a new matrix `answer` where `answer[row][col]` is the **rank** of `matrix[row][col]`. > >The rank is an integer that represents how large an element is compared to other elements. It is calculated using the following rules: > >* The rank is an integer starting from 1. >* If two elements `p` and `q` are in the **same row or column**, then: >* * If **`p < q`** then **`rank(p) < rank(q)`** >* * If **`p == q`** then **`rank(p) == rank(q)`** >* * If **`p > q`** then **`rank(p) > rank(q)`** >* The rank should be **as small as possible**. > >It is guaranteed that answer is unique under the given rules. ![](https://i.imgur.com/KWFYntI.png) :::info **Example 1:** **Input:** matrix = [[1,2],[3,4]] **Output:** [[1,2],[2,3]] **Explanation:** The rank of matrix[0][0] is 1 because it is the smallest integer in its row and column. The rank of matrix[0][1] is 2 because matrix[0][1] > matrix[0][0] and matrix[0][0] is rank 1. The rank of matrix[1][0] is 2 because matrix[1][0] > matrix[0][0] and matrix[0][0] is rank 1. The rank of matrix[1][1] is 3 because matrix[1][1] > matrix[0][1], matrix[1][1] > matrix[1][0], and both matrix[0][1] and matrix[1][0] are rank 2. ::: ![](https://i.imgur.com/xGTUSU4.png) :::info **Example 2:** **Input:** matrix = [[7,7],[7,7]] **Output:** [[1,1],[1,1]] ::: ![](https://i.imgur.com/tkjmmgh.png) :::info **Example 3:** **Input:** matrix = [[20,-21,14],[-19,4,19],[22,-47,24],[-19,4,19]] **Output:** [[4,2,3],[1,3,4],[5,1,6],[1,3,4]] ::: ![](https://i.imgur.com/loUytZA.png) :::info **Example 4:** **Input:** matrix = [[7,3,6],[1,4,5],[9,8,2]] **Output:** [[5,1,4],[1,2,3],[6,3,1]] ::: :::warning **Constraints:** * m == matrix.length * n == matrix[i].length * 1 <= m, n <= 500 * -109 <= matrix[row][col] <= 109 ::: --- ### Approach 1 : Union Find **`216 ms ( 83.58% )`** **`O( NNlog(MN) )`** :::success * 將元素的位置轉換成一維記錄到 **`map`** ---> **`index = i * n + j`**。 > m = 3, n = 3。 > row = 1, col = 1 ---> **`index = 1 * 3 + 1 = 4`**。 * **`root, rank`** 大小為 `m + n` ---> **`0 ~ m - 1 = row`**。 ---> **`m ~ m + n - 1 = col`**。 ::: :::success **Union Find** : 假設 `A 跟 B 一組`,給他們編號 `B`,後來又有 `B 跟 C 一組`,這時給他們編號 `C`,但是 `A` 也是跟 `B、C` 一組的,所以 `A` 同時也需要一起更新。 下面的方法會將 `row、col` 各做一次尋找。 ::: * **`map<int, vector<int>> list`** 紀錄所有元素的位置。 **`vector<int> rank(m + n, 0)`** 紀錄當前 `row、col` 的 `rank` 最大值。 **`vector<int> root(m + n, 0)`** 用於紀錄 `Union Find` 的組別。 1. 先將所有元素存入 `list`。 2. 因為 `list` 已經是排序過的,所以從頭開始遍歷,可以確保當前元素是最大值,接著判斷該元素下的所有 `index`。 > * 先將 `root` 初始化。 > * 接著使用 `Union Find` 將大小相同的元素分組,同時更新 `rank` 的最大值,判斷哪些 `col 或 row 相同`,他們的 `rank` 必須相同。 > * 透過剛剛的分組,賦予每個組別 `rank`。 > ---> **`rank2`** 紀錄下一輪的值,可以避免相同組別被賦予到不同的值,最後再丟回 **`rank`**。 >```cpp=38 > rank2[i] = rank[group] + 1; > rank2[j + m] = rank[group] + 1; >``` > 以 `2` 為例的 `Union Find`。 ![](https://i.imgur.com/UbvALep.png) ![](https://i.imgur.com/7ovUmEg.png) > 給 `rank` 值 ---> 找 `group`。 >![](https://i.imgur.com/PMxB7Uh.png) ```cpp=1 class Solution { public: vector<vector<int>> matrixRankTransform(vector<vector<int>>& matrix) { int m = matrix.size(), n = matrix[0].size(); map<int, vector<int>> list; // val, index for (int i=0; i<m; ++i) { for (int j=0; j<n; ++j) { list[matrix[i][j]].push_back(i * n + j); } } vector<int> rank(m + n, 0); vector<vector<int>> ans(m, vector<int>(n)); for (auto & it : list) { vector<int> root(m + n, 0); // for Union find ( 0~n-1 = row / n ~ n+m-1 = col ) for(int i=0; i<m+n; i++){ root[i] = i; } // use Union find to find group for (auto & a: it.second) { int i = a / n, j = a % n; int r1 = find(root, i), r2 = find(root, j + m); root[r1] = r2; // make row point to column rank[r2] = max(rank[r1], rank[r2]); } // set rank auto rank2 = rank; for (auto & a : it.second) { int i = a / n, j = a % n; int group = find(root, i); ans[i][j] = rank[group] + 1; rank2[i] = rank[group] + 1; rank2[j + m] = rank[group] + 1; } rank = rank2; } return ans; } // Union find int find(vector<int>& root, int x) { if (root[x] != x) root[x] = find(root, root[x]); // update root[x] return root[x]; } }; ```