【矩阵二分】力扣378. 有序矩阵中第 K 小的元素

给你一个 n x n 矩阵 matrix ,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。

请注意,它是 排序后 的第 k 小元素,而不是第 k 个 不同 的元素。

你必须找到一个内存复杂度优于 O(n2) 的解决方案。

示例 1:

输入:matrix = [[1,5,9],[10,11,13],[12,13,15]], k = 8

输出:13

解释:矩阵中的元素为 [1,5,9,10,11,12,13,13,15],第 8 小元素是 13

示例 2:

输入:matrix = [[-5]], k = 1

输出:-5

二分

csharp 复制代码
class Solution {
public:
    bool check(vector<vector<int>>& matrix, int mid, int k, int n){
        int i = n - 1;
        int j = 0;
        int num = 0;
        while(i >= 0 && j < n){
            if(matrix[i][j] <= mid){
                num += i + 1;
                j++;
            }
            else{
                i--;
            }
        }
        return k <= num;
    }


    int kthSmallest(vector<vector<int>>& matrix, int k) {
        int n = matrix.size();
        int left = matrix[0][0];
        int right = matrix[n-1][n-1];
        while(left < right){
            int mid = (left + right) >> 1;
            if(check(matrix, mid, k, n)){
                right = mid;
            }
            else{
                left = mid + 1;
            }
        }
        return left;
    }
};

时间复杂度:O(nlog(r−l)) ,二分查找进行次数为 O(log(r−l)),每次操作时间复杂度为 O(n)。
空间复杂度:O(1)

矩阵中最小的元素是matrix[0][0],最大的元素是matrix[n-1][n-1],这道题使用二分查找的思想就是我们从最小数到最大数之间任意挑一个数字作为mid。假设mid = 8,根据图片,矩阵可以分成两个部分,一个部分全部小于等于8,另外一个部分全部大于8。我们可以统计左上部分小于等于8的数的数量,看8在排序后是第几小的数(因为图片有多个8,所以返回的是8是第几小的数的最大情况,即升序排列中最右边的8的位置)。

所以在二分查找中,我们从取left + right除以2的值为mid,如果在check函数中得出来左上部分的数量大于等于我们所期待的k,那么就说明我们的取的mid大于等于实际元素,这时候我们就将right = mid,缩小他的上界。如果左上部分数量小于我们所期待的k,说明我们取的mid比实际元素要小,我们令left = mid + 1,增加他的下界。

很多人会疑问left怎么确保一定是矩阵中的数?

如题解中所说,如果 num >= k,那么说明最终答案 x <= mid;如果 num < k,那么说明最终答案 x > mid。 在最后一次迭代时,check返回的结果为false,即 num < k,说明 x > mid,又因为 x <= right。当 left = mid + 1 后,left >= righ,while循环结束。此时有 mid < x <= right <= left = mid + 1,即 mid < x <= mid + 1。可得 x = mid + 1 = left。

相关推荐
链巨人12 分钟前
通俗理解模型梯度、海森矩阵、模型参数,以及它们之间的关系
人工智能·线性代数·矩阵
听风吹等浪起15 分钟前
【SwinTransformer 全维度改进方案矩阵】—— 覆盖注意力、多尺度、通道/空间增强,适配CV全场景的工业级优化库
人工智能·深度学习·线性代数·计算机视觉·矩阵
im_AMBER1 小时前
Leetcode 145 回文数 | 加一
数据结构·算法·leetcode
放下华子我只抽RuiKe51 小时前
文本处理与RNN:硬核实战笔记
人工智能·rnn·深度学习·神经网络·线性代数·机器学习·矩阵
Tisfy1 小时前
LeetCode 2906.构造乘积矩阵:前后缀分解
算法·leetcode·前缀和·矩阵·题解·前后缀分解
旖-旎2 小时前
前缀和(和为K的子数组)(5)
c++·算法·leetcode·前缀和·哈希算法·散列表
凌波粒2 小时前
LeetCode--203.移除链表元素(链表)
java·算法·leetcode·链表
Q741_1472 小时前
力扣经典模板题 前缀积 力扣 2906. 构造乘积矩阵 每日一题 哈希表 找规律 力扣 13. 罗马数字转整数 C++
算法·leetcode·前缀和·矩阵
北顾笙9802 小时前
day05-数据结构力扣
数据结构·leetcode·哈希算法
1104.北光c°2 小时前
Leetcode206.反转链表 迭代+递归 【hot100算法个人笔记】【java写法】
java·数据结构·笔记·算法·leetcode·链表·反转链表