Kth Smallest Element in a Sorted Matrix

1. 解析

题目大意,在行和列有序的二维矩阵中查找第k个最小的数。

2. 分析

刚开始看到题目,我以为利用Search a 2D Matrix II的思路解决就可以,折腾半天发现,好像有点不太一样。其实本质还是一样的,只不过我没想出来。比较容易想到的解法就是利用优先队列priority_queue,默认是大根堆,遍历矩阵,将矩阵中的每一个元素放进堆当中,若堆中元素的个数大于k,去掉堆顶元素,这样可以保证堆中存储的始终是矩阵中前k个最小的数,最后将返回堆顶即可。

class Solution {
public:
    int kthSmallest(vector<vector<int>>& matrix, int k){
        priority_queue<int> res;
        for (auto nums : matrix){
            for (int num : nums){
                res.push(num);
                if (res.size() > k) res.pop(); //若当前堆中元素大于k个,删除堆顶元素
            }
        }
        return res.top();
    }
};

3. 折半查找解法 

参考@Grandyang的思路,为了和Search a 2D Matrix II联系起来,我主要就讲解search2的解法。因为是行和列有序,所以若以左下角的元素为起点,那么往右移动元素递增,往上移动元素递减,根据这个可以统计出矩阵中小于target目标的个数。且左上角的元素left小于右下角的元素right,这样可以采用二分查找的方式,每次以mid = (left + right) / 2作为目标值,然后统计当前小于目标值的个数cnt,若cnt < k,说明当前元素mid无法获取k个元素,left = mid + 1; 反之, 在(left, mid) 范围内能够获取大于k个元素,缩小范围成right = mid,在(left, mid) 范围查找。

class Solution {
public:
    int kthSmallest(vector<vector<int>>& matrix, int k){
        int left = matrix[0][0], right = matrix.back().back();
        
        while (left < right){
            int mid = (left + right) / 2;
            int cnt = search1(matrix, mid);
            //int cnt = search2(matrix, mid);
            if (cnt < k) left = mid + 1;
            else right = mid;
        }
        return left;
    }
    int search1(vector<vector<int>>& matrix, int target){
        int res = 0;
        for (auto nums : matrix){
            res += upper_bound(nums.begin(), nums.end(), target) - nums.begin();
        }
        return res;
    }
    int search2(vector<vector<int>>& matrix, int target){
        int res = 0;
        int i = matrix.size() - 1, j = 0; //左下角坐标
        while (i >= 0 && j < matrix[i].size()){
            if (matrix[i][j] <= target){
                res += i + 1;
                j++;
            }
            else{
                i--;
            }
        }
        return res;
    }
};

4. 类似题目 

Search a 2D Matrix II

[1]https://www.cnblogs.com/grandyang/p/5727892.html

[2]https://www.cnblogs.com/Tang-tangt/p/9291018.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值