LeetCode 1738. 找出第 K 大的异或坐标值

1738. 找出第 K 大的异或坐标值

给你一个二维矩阵 matrix 和一个整数 k ,矩阵大小为 m x n 由非负整数组成。

矩阵中坐标 (a, b) 的 目标值 可以通过对所有元素 matrix[i][j] 执行异或运算得到,其中 i 和 j 满足 0 <= i <= a < m 且 0 <= j <= b < n下标从 0 开始计数)。

请你找出 matrix 的所有坐标中第 k 大的目标值(k 的值从 1 开始计数)。

示例 1:

输入:matrix = [[5,2],[1,6]], k = 1
输出:7
解释:坐标 (0,1) 的目标值是 5 XOR 2 = 7 ,为最大的目标值。

示例 2:

输入:matrix = [[5,2],[1,6]], k = 2
输出:5
解释:坐标 (0,0) 的目标值是 5 = 5 ,为第 2 大的目标值。

示例 3:

输入:matrix = [[5,2],[1,6]], k = 3
输出:4
解释:坐标 (1,0) 的目标值是 5 XOR 1 = 4 ,为第 3 大的目标值。

示例 4:

输入:matrix = [[5,2],[1,6]], k = 4
输出:0
解释:坐标 (1,1) 的目标值是 5 XOR 2 XOR 1 XOR 6 = 0 ,为第 4 大的目标值。

提示:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= m, n <= 1000
  • 0 <= matrix[i][j] <= 10^6
  • 1 <= k <= m * n

提示 1

Use a 2D prefix sum to precalculate the xor-sum of the upper left submatrix.

 

解法1:二维异或前缀 + 排序

思路与算法

我们用 ⊕ 表示按位异或运算。 由于「按位异或运算」与「加法运算」有着十分相似的性质,它们都满足

交换律: a⊕b=b⊕a

结合律: (a⊕b)⊕c=a⊕(b⊕c)

因此我们可以使用「前缀和」这一技巧对按位异或运算的结果进行维护。

由于本题中给定的矩阵 matrix 是二维的,因此我们需要使用二维前缀和。

设二维前缀和 pre(i, j) 表示矩阵 matrix 中所有满足 0≤x<i 且 0≤y<j 的元素执行按位异或运算的结果。与一维前缀和类似,要想快速得到 pre(i,j),我们需要已经知道 pre(i−1,j),pre(i,j−1) 以及 pre(i−1,j−1) 的结果,即:

pre(i,j)=pre(i−1,j)⊕pre(i,j−1)⊕pre(i−1,j−1)⊕matrix(i,j)

下图给出了该二维前缀和递推式的可视化展示。

当我们将 pre(i−1,j) 和 pre(i,j−1) 进行按位异或运算后,由于对一个数 x 异或两次 y,结果仍然为 x 本身,即:

x⊕y⊕y=x

因此 pre(i−1,j−1) 对应区域的按位异或结果被抵消,我们需要将其补上,并对位置 (i,j) 的元素进行按位异或运算,这样就得到了 pre(i,j)。

在得到了所有的二维前缀和之后,我们只需要找出其中第 k 大的元素即为答案。这一步我们可以直接将 mn 个二维前缀和进行排序后返第 k 大的元素。

Java版:

class Solution {
    public int kthLargestValue(int[][] matrix, int k) {
        int m = matrix.length;
        int n = matrix[0].length;
        int[][] prexor = new int[m + 1][n + 1];
        List<Integer> res = new ArrayList<Integer>();
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                prexor[i + 1][j + 1] = prexor[i + 1][j] ^ prexor[i][j + 1] ^ prexor[i][j] ^ matrix[i][j];
                res.add(prexor[i + 1][j + 1]);
            }
        }
        // 排序方式1
        Collections.sort(res, new Comparator<Integer>() {
            public int compare(Integer num1, Integer num2) {
                return num2 - num1;
            }
        });
        // 排序方式2
        // res.sort(new Comparator<Integer>() {
        //     public int compare(Integer num1, Integer num2) {
        //         return num2 - num1;
        //     }
        // });
        return res.get(k - 1);
    }
}

Python3版:

class Solution:
    def kthLargestValue(self, matrix: List[List[int]], k: int) -> int:
        m = len(matrix)
        n = len(matrix[0])
        prexor = [[0] * (n + 1) for _ in range(m + 1)]
        res = []
        for i in range(m):
            for j in range(n):
                prexor[i + 1][j + 1] = prexor[i + 1][j] ^ prexor[i][j + 1] ^ prexor[i][j] ^ matrix[i][j]
                res.append(prexor[i + 1][j + 1])
        res.sort(reverse=True)
        return res[k - 1]

复杂度分析

  • 时间复杂度:O(mnlog(mn))其中 m 和 n 分别为 matrix 的行数和列数。计算二维前缀和的时间复杂度为 O(mn),排序的时间复杂度为 O(mnlog(mn)),因此总时间复杂度为 O(mnlog(mn))。
  • 空间复杂度:O(mn),即为存储二维前缀和需要的空间。
  • 35
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值