【每日一题Day98】LCLC1632矩阵转换后的秩 | TreeMap+并查集

简介: 然后遍历TreeMap,使用并查集处理存在相同元素时的情况,将元素分为几个连通块,对于每个连通块,里面所有元素对应的秩为这些行或列的最大秩加 1。

矩阵转换后的秩【LC1632】


给你一个 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差2的 改完一个又来一个 累了 明天再改了 =(

怎么也想不到是并查集…


  • 思路:


。将矩阵组成三元组{值,横坐标,纵坐标},根据值从小到大排序,按照顺序赋予秩


  • 如果当前值在同行或者同列中未出现过,那么秩为该行该列秩的最大值+1,
  • 如果当前值在同行或者同列中出现过,那么这些位置的秩为这些行列中秩的最大值+1,因此需要统计每行每列秩的最大值


  • 实现【并查集】


。使用TreeMap存放某个值的所有下标,key值为数值,value为动态数组存放下标,key值从小到大排序


。然后遍历TreeMap,使用并查集处理存在相同元素时的情况,将元素分为几个连通块,对于每个连通块,里面所有元素对应的秩为这些行或列的最大秩加 1。


  • 首先将某个数值的所有row和col加入并查集中,列值对应的下标+m【将二维化为一维】
  • 然后对于每一个连通块找到所有节点秩的最大值,记录在rank数组中,下标为该连通块的根节点序号
  • 再对该连通块内每一个位置赋予结果为最大秩+1
  • 最后对并查集复原
  • 并查集中size属性不是必须的,可以去除


// 并查集类
class UnionFind {
    private int[] p;// 值
    private int[] size;// 每个节点的子节点个数(包括自身) 非必须 可去除
  // 初始化
    public UnionFind(int n) {
        p = new int[n];
        size = new int[n];
        for (int i = 0; i < n; ++i) {
            p[i] = i;
            size[i] = 1;
        }
    }
  // 找到节点x的根
    public int find(int x) {
        if (p[x] != x) {
            p[x] = find(p[x]);
        }
        return p[x];
    }
  // 在并查集中加入a->b的根
    public void union(int a, int b) {
        int pa = find(a), pb = find(b);
        if (pa != pb) {
            if (size[pa] > size[pb]) {
                p[pb] = pa;
                size[pa] += size[pb];
            } else {
                p[pa] = pb;
                size[pb] += size[pa];
            }
        }
    }
  // 重置并查集
    public void reset(int x) {
        p[x] = x;
        size[x] = 1;
    }
}
class Solution {
    public int[][] matrixRankTransform(int[][] matrix) {
        int m = matrix.length, n = matrix[0].length;
        // 存放值对应的下标
        TreeMap<Integer, List<int[]>> d = new TreeMap<>();
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                d.computeIfAbsent(matrix[i][j], k -> new ArrayList<>()).add(new int[] {i, j});
            }
        }
        int[] rowMax = new int[m];
        int[] colMax = new int[n];
        int[][] ans = new int[m][n];
        // 构造并查集
        UnionFind uf = new UnionFind(m + n);
        int[] rank = new int[m + n];
        // 从小到大遍历某个值的所有下标
        for (var ps : d.values()) {
            // ps:坐标 p[0]:row p[1]:col p[1]+m:newCol【二维化一维】
            // 将row->col+m这条边加入并查集
            // 如果有以下三个位置的数值相同[row1,col1][row1,col2][row2,col2][row3,col3]
            // 那么节点row1,row2,col1+m,col2+m会有同一个根节点
            // 节点row3,col3会有同一个根节点
            for (var p : ps) {
                uf.union(p[0], p[1] + m);
            }
            // 对于每个连通块,找到里面所有元素对应的行或列的最大秩
            for (var p : ps) {
                int i = p[0], j = p[1];
                rank[uf.find(i)] = Math.max(rank[uf.find(i)], Math.max(rowMax[i], colMax[j]));
            }
            // 对于每个连通块,其秩为最大秩+1
            for (var p : ps) {
                int i = p[0], j = p[1];
                ans[i][j] = 1 + rank[uf.find(i)];
                rowMax[i] = ans[i][j];
                colMax[j] = ans[i][j];
            }
            // 处理完一个连通块之后需要将并查集复原
            for (var p : ps) {
                uf.reset(p[0]);
                uf.reset(p[1] + m);
            }
        }
        return ans;
    }
}
作者:ylb
链接:https://leetcode.cn/problems/rank-transform-of-a-matrix/solutions/2075493/by-lcbin-ll29/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


。复杂度


  • 时间复杂度:O(m×n×(log⁡m+log⁡n))。并查集的合并次数是O(m×n),构建TreeMap的复杂度为 O(m×n×(log⁡m+log⁡n)),


  • 空间复杂度:O(m×n)。并查集的空间复杂度为O(m+n),TreeMap的空间复杂度为O(m×n)。
目录
相关文章
|
7月前
【每日一题Day146】给定行和列的和求可行矩阵 | 贪心
【每日一题Day146】给定行和列的和求可行矩阵 | 贪心
55 0
【LeetCode-每日一题】-378. 有序矩阵中第K小的元素
【LeetCode-每日一题】-378. 有序矩阵中第K小的元素
|
2月前
|
算法 测试技术 C++
【动态规划算法】蓝桥杯填充问题(C/C++)
【动态规划算法】蓝桥杯填充问题(C/C++)
|
4月前
|
算法 索引
【算法】二分算法——山脉数组的峰顶索引
【算法】二分算法——山脉数组的峰顶索引
|
6月前
|
存储 算法
算法训练,牛客.判断是不是平衡二叉树 牛客.最大子矩阵两个数组的交集牛客.数组中两个字符串的最小距离
算法训练,牛客.判断是不是平衡二叉树 牛客.最大子矩阵两个数组的交集牛客.数组中两个字符串的最小距离
算法训练,牛客.判断是不是平衡二叉树 牛客.最大子矩阵两个数组的交集牛客.数组中两个字符串的最小距离
|
7月前
|
存储 机器学习/深度学习 人工智能
【算法基础】基础算法(三)--(双指针算法、位运算、离散化、区间合并)
【算法基础】基础算法(三)--(双指针算法、位运算、离散化、区间合并)
|
7月前
|
存储 人工智能 Java
每日一题《剑指offer》数组篇之构建乘积数组
每日一题《剑指offer》数组篇之构建乘积数组
48 0
每日一题《剑指offer》数组篇之构建乘积数组
|
7月前
|
存储 BI
【剑指offer】-构建乘积数组-42/67
【剑指offer】-构建乘积数组-42/67
|
存储 人工智能 算法
剑指offer 74. 构建乘积数组
剑指offer 74. 构建乘积数组
60 0
|
算法 测试技术
分治法解二维的最近对问题,算法分析与代码实现,蛮力法与分治法解决二维的最近对问题的区别
分治法解二维的最近对问题,算法分析与代码实现,蛮力法与分治法解决二维的最近对问题的区别
377 0