• 1632. 矩阵转换后的秩 并查集+排序


    1632. 矩阵转换后的秩

    给你一个 m x n 的矩阵 matrix ,请你返回一个新的矩阵 answer ,其中 answer[row][col] 是 matrix[row][col] 的秩。

    每个元素的  是一个整数,表示这个元素相对于其他元素的大小关系,它按照如下规则计算:

    • 秩是从 1 开始的一个整数。
    • 如果两个元素 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
    • -1e9 <= matrix[row][col] <= 1e9

    来源:力扣(LeetCode)
    链接:https://leetcode.cn/problems/rank-transform-of-a-matrix
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    做题结果

    成功,不过写了好久,好几个小时。开始的做法是 图+拓扑,发现有问题,会不满足同行同列一起变化的条件。更换了思路,变成并查集+排序最终通过

    方法:并查集+排序

    1. 并查集并在哪里?这题用并查集是藏的很好的。它的并在于相同数字的行列值相同,这意味着,他们需要一起改变。数组中完全有可能有多个转角,从而达成间接关系,而一起改变。如图,多个3可以一起改变,但是并不是值相同一定一起改变。红色的3和其他3的行列都不相同,因此,不和其他3一起改变。因此我们需要根据值和位置进行分组,于是就用到了并查集。

    1. class Solution {
    2. int[] parent;
    3. int[] sizes;
    4. public int[][] matrixRankTransform(int[][] matrix) {
    5. int m = matrix.length;
    6. int n = matrix[0].length;
    7. int[][] ans = new int[m][n];
    8. parent = new int[m*n];
    9. sizes = new int[m*n];
    10. for(int i = 0; i < m*n; i++){
    11. parent[i] = i;
    12. sizes[i] = 1;
    13. }
    14. //并查集
    15. for(int i = 0; i < m; i++){
    16. Map map = new HashMap<>();
    17. for(int j = 0; j < n; j++){
    18. if(map.containsKey(matrix[i][j])) connect(map.get(matrix[i][j]),i*n+j);
    19. else map.put(matrix[i][j],i*n+j);
    20. }
    21. }
    22. for(int j = 0; j < n; j++){
    23. Map map = new HashMap<>();
    24. for(int i = 0; i < m; i++){
    25. if(map.containsKey(matrix[i][j])) connect(map.get(matrix[i][j]),i*n+j);
    26. else map.put(matrix[i][j],i*n+j);
    27. }
    28. }
    29. Set[] cnt = new HashSet[m*n];
    30. Arrays.setAll(cnt,o->new HashSet<>());
    31. for(int i = 0; i < m*n; i++){
    32. int p = root(i);
    33. cnt[p].add(i);
    34. }
    35. List list = new ArrayList<>();
    36. for(int i = 0; i < m*n; i++) list.add(i);
    37. list.sort((a,b)->matrix[a/n][a%n]-matrix[b/n][b%n]);
    38. int[] mlines = new int[m];
    39. int[] mcols = new int[n];
    40. for(int i = 0; i < m*n; i++){
    41. int id = list.get(i);
    42. int x = id/n;
    43. int y = id%n;
    44. //System.out.println(matrix[x][y]);
    45. int rid = root(id);
    46. sizes[rid]--;
    47. if(sizes[rid]==0){
    48. int value = 0;
    49. for(Integer item:cnt[rid]){
    50. value = Math.max(Math.max(mlines[item/n]+1,mcols[item%n]+1),value);
    51. }
    52. for(Integer item:cnt[rid]){
    53. ans[item/n][item%n]=value;
    54. mlines[item/n]=value;
    55. mcols[item%n]=value;
    56. }
    57. }
    58. }
    59. return ans;
    60. }
    61. private void connect(int a, int b){
    62. int ra = root(a);
    63. int rb = root(b);
    64. if(ra==rb) return;
    65. if(sizes[ra]>=sizes[rb]){
    66. parent[rb] = ra;
    67. sizes[ra] += sizes[rb];
    68. }else{
    69. parent[ra] = rb;
    70. sizes[rb] += sizes[ra];
    71. }
    72. }
    73. private int root(int a){
    74. while(parent[a]!=a){
    75. parent[a] = parent[parent[a]];
    76. a = parent[a];
    77. }
    78. return a;
    79. }
    80. }

     2. 分组后的处理。小的数字一定要分配更小的值,大的数字一定分配更大的值,因此,我们完全可以把所有元素的行列索引,按照从小到大排序,依次放入。

    3. 相同值是需要一起放入的。所以当一个值完成放置后,需要处理对应并查集位置-1,当所有并查集元素都完成放入操作后,即可填写这一组并查集元素的值。

    4. 每次填好id后,更新对应行列的最大id。后续放入的值是并查集的所有元素,行列填入的最大值+1。原因是这些元素必须要填写相同的值,又要保证不同元素值不同。

  • 相关阅读:
    如何防御udp攻击
    .NET AsyncLocal 避坑指南
    云原生之深入解析如何使用Vcluster Kubernetes加速开发效率
    智能汽车安全:保护车辆远程控制和数据隐私
    C++学习:动态内存分配new
    LeetCode-1774. 最接近目标价格的甜点成本【数组,背包问题,优化暴力,回溯】
    mysql5.7.21 安装与使用
    LeetCode-475. 供暖器-Java-easy
    linux 里面卸载jdk
    第8关:使用递归
  • 原文地址:https://blog.csdn.net/yu_duan_hun/article/details/126681940