leetcode378.有序矩阵中第K小的元素(中等)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
n^2约等于10的5次方,写成n
解法一:排序。 时间复杂度O(nlogn)

class Solution {
public:
    int kthSmallest(vector<vector<int>>& matrix, int k) {
        
        vector<int> nums;
        for (auto& row : matrix) {
            for (auto& each : row) {
                nums.push_back(each);
            }
        }
        sort(nums.begin(), nums.end());
        return nums[k - 1];
    }
};

解法二:优先队列(大顶堆)。 时间复杂度O(nlogn)

class Solution {
public:
    int kthSmallest(vector<vector<int>>& matrix, int k) {
        
        priority_queue<int> pq;
        for (auto& row : matrix) {
            for (auto& each : row) {
                if (pq.size() < k) pq.push(each);
                else if (each < pq.top()) {
                    pq.pop();
                    pq.push(each);
                } 
            }
        }
        return pq.top();
    }
};

解法三:多路归并 (利用了行递增的特点)时间复杂度O(nlogn)
具体:用优先队列保存每一行的最小值,如果该元素所在位置后面还有元素就把下一个元素放到堆中。top出k-1次后top即需要的值。
易错点:维护的是一个小顶堆而不是大顶堆

class Solution {
public:
    struct cmp {
        bool operator()(vector<int>& v1, vector<int>& v2) const{
            return v1[0] > v2[0]; //'>'表示小顶堆
        }
    };
    int kthSmallest(vector<vector<int>>& matrix, int k) {
        
        vector<int> elem;
        priority_queue<vector<int>, vector<vector<int>>, cmp> pq;
        int n = matrix.size();
        for (int i = 0; i < n ;++i) {
            pq.push(vector<int>{matrix[i][0], i, 0});
        }
        for (int i = 0; i < k - 1; ++i) {
            auto tp = pq.top();
            pq.pop();
            if (tp[2] < n - 1) {
                pq.push(vector<int>{matrix[tp[1]][tp[2] + 1], tp[1], tp[2] + 1});
            }
        }
        return pq.top()[0];
    }
};

解法四:二分查找(同时利用行 列均递增的特点)时间复杂度O(nlog(r-l)) 最优!!!
细节:将矩阵分成两部分,左边所有的元素均小于等于mid,统计出左半部分元素的个数cnt,也就是找出一个最小的mid值,满足cnt >= k

class Solution {
public:
    int kthSmallest(vector<vector<int>>& matrix, int k) {
        
        int n = matrix.size();
        int l = matrix[0][0] - 1, r = matrix[n - 1][n - 1] + 1;
        while (l + 1 < r) {
            int mid = l + (r - l) / 2;
            int cnt = 0; 
            int j = 0;
            for (int i = 0; i < n; ++i) {
                if (i == 0) { //i == 0时用二分
                    j = upper_bound(matrix[0].begin(),matrix[0].end(),mid)-matrix[0].begin();
                }else { //i > 0时j向左移动
                    while (j - 1 >= 0 && matrix[i][j - 1] > mid) --j;
                }
                if (j == 0) break;
                cnt += j;
            }
            if (cnt >= k) r = mid;
            else l = mid;     
        }
        return r;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值