[LeetCode] (medium) 378. Kth Smallest Element in a Sorted Matrix

https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/

Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth smallest element in the matrix.

Note that it is the kth smallest element in the sorted order, not the kth distinct element.

Example:

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

return 13.

Note: 
You may assume k is always valid, 1 ≤ k ≤ n2.


 参考:https://www.cnblogs.com/grandyang/p/5727892.html

强化版的二分查找,注意到二分查找的搜索空间对应于所有可能的解组成的解空间,所以在这道题里最外层二分的对象是第k的元素的可能值(而不是索引),为了获得当前mid的性质,我们需要统计矩阵中小于mid的元素的个数(严格小于还是小于等于会在下文中讨论),这里又可以针对每一行使用一次二分。

注意到二分有两种方法,对应的分别是“不小于target的最小值/位置(或小于target的最大值/位置)”和“不大于target的最大值/位置(或大于target的最小值/位置)”,这里必须要两者结合使用。如果内部二分使用的是前者,则统计的是mid在矩阵中的最小排名,所以外层二分需要使用后者,得到的是最小排位刚刚好大于k的值,则减一即为返回值。两者交换同理。

同时注意到一个二分的小细节,就是在取mid时为了确保mid向lo去尾,我习惯于写成mid = (lo+hi)/2,这个在非负数范畴(传统的下标查找)内没有问题,但是在涉及负数(这道题的普通解查找)时,这个式子会因为向零去尾的特点导致mid向hi去尾,从而造成迭代无法缩小问题规模。所以更好的写法应该是mid = lo+(hi-lo)/2,可以确保向lo去尾的特征。

class Solution {
public:
    int n;
    int kthSmallest(vector<vector<int>>& matrix, int k) {
        static int fast_io = []() { std::ios::sync_with_stdio(false); cin.tie(nullptr); return 0; }();
        n = matrix.size();
        int lo = matrix[0][0];
        int hi = matrix[n-1][n-1]+1;
        int mid, cnt;
        while(lo < hi){
            mid = lo+(hi-lo)/2; //这么做可以确保不管是正负数都向lo去尾
            cnt = 1;
            for(int i = 0; i < n; ++i){
                // cnt += binary_search(matrix, i, mid);
                cnt += (lower_bound(matrix[i].begin(), matrix[i].end(), mid)-matrix[i].begin());
                // cnt += search_less(matrix, mid);
            }
            if(cnt > k) hi = mid;
            else lo = mid+1;
        }
        return lo-1;
    }
    
    //这个函数不对,因为原始矩阵不是严格单调
    //只能修改后用于计算<=的数量
    int search_less(vector<vector<int>>& matrix, int target){
        int r = n-1, c = 0, result = 0;
        while(r >= 0 && c < n){
            if(matrix[r][c] < target){
                result += (r+1);
                ++c;
            }
            else{
                --r;
            } 
        }
        return result;
    }
    
    //返回小于target的最大秩+1,即小于target的元素的个数
    int binary_search(vector<vector<int>>& matrix, int row, int target){
        int lo = -1;
        int hi = n-1;
        int mid;
        while(lo < hi){
            mid = (lo + hi + 1)/2;
            if(matrix[row][mid] < target) lo = mid;
            else hi = mid-1;
        }
        return lo+1;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值