JAVA程序设计:矩阵转换后的秩(LeetCode: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
-109 <= matrix[row][col] <= 109

思路:比赛时觉得题目好难,下来仔细想想其实考察的知识点还是行和列的联动问题,我们考虑将矩阵中所有数从小到大进行遍历,对于每个数,我们需要让行和列建立起关系,因为我们需要这个元素的秩在行和列中都是合法的,除此之外,对于相同大小的元素,我们需要特殊处理,因为假如两个元素属于同一行或者同一列,则我们需要保证这两个元素的秩是相同的,这个时候我们需要借助并查集辅助我们完成这项工作,因为相同的元素可能会牵扯进来更多的行和列,我们需要保证这些行和列都是合法的。

class Solution {

    private int[] f;

    public int[][] matrixRankTransform(int[][] matrix) {
        int m = matrix.length;
        int n = matrix[0].length;
        int[][] ret = new int[m][n];
        int[] row = new int[m];
        int[] col = new int[n];
        PriorityQueue<int[]> q = new PriorityQueue<>((a, b) -> a[0] - b[0]);
        for (int i = 0; i < m; i++)
            for (int j = 0; j < n; j++)
                q.add(new int[]{matrix[i][j], i, j});
        while (!q.isEmpty()) {
            int target = q.peek()[0];
            List<int[]> list = new ArrayList<>();
            while (!q.isEmpty() && q.peek()[0] == target)
                list.add(q.poll());
            f = new int[n + m];
            for (int i = 0; i < n + m; i++) f[i] = i;
            for (int[] arr : list) {
                int t1 = find(arr[1]);
                int t2 = find(arr[2] + m);
                if (t1 != t2)
                    f[t1] = t2;
            }
            Map<Integer, List<int[]>> map = new HashMap<>();
            for (int[] arr : list) {
                int t = find(arr[1]);
                if (!map.containsKey(t))
                    map.put(t, new ArrayList<>());
                map.get(find(arr[1])).add(arr);
            }
            //System.out.println(list.size());
            for (List<int[]> group : map.values()) {
                int rank = 0;
                for (int[] arr : group) {
                    int i = arr[1], j = arr[2];
                    rank = Math.max(rank, Math.max(row[i], col[j]) + 1);
                }
                for (int[] arr : group) {
                    int i = arr[1], j = arr[2];
                    ret[i][j] = rank;
                    row[i] = Math.max(row[i], rank);
                    col[j] = Math.max(col[j], rank);
                }
            }
        }
        return ret;
    }

    private int find(int x) {
        if (f[x] == x)
            return f[x];
        return f[x] = find(f[x]);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值