LeetCode 378. Kth Smallest Element in a Sorted Matrix 解题报告

LeetCode 378. 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.

You may assume k is always valid, 1kn2 .


示例

Example


限制条件

没有明确给出。


解题思路

我的思路:

求第K个最大或最小的数,感觉可以用堆去完成,所以这道题我是用一个大根堆完成的。
遍历整个矩阵,把所有元素都插入到堆中,当堆的大小超过k时就弹出根节点,这样最后堆中保存的是前k小的元素,题目只要第k小的元素,所以直接把堆的根节点取出并返回就Accept了。

参考思路1

同样是使用堆数据结构,堆中保存的是元素值跟元素的坐标(i,j)。根据矩阵行列皆有序的特性,先把所有行的第一个元素放入到堆中。然后每次从堆中弹出最小的元素,并把弹出元素所在行的下一个元素放入堆中(如果没到该行的边界,存在下一个元素的话),执行这个过程k次,第k次的结果就是第k个最小的元素。
这算法的原理是利用了每行第一个元素都是该行的最小元素,并且下次放入的元素是当前被弹出元素所在行的下一个元素,这操作保证了堆中保存着所有行目前最小的元素,因此从中弹出的必定是当前矩阵最小的元素,进行k次的话,那么最后弹出的就会是第k小的元素。

参考思路2

这道题也可以用二分查找的思想去做。扫描矩阵元素,统计小于等于中间值的个数,并与k对比,根据对比结果维护左右边界[l,r],使得第k小的元素始终在[l,r]之间,当l=r时,r跟l就是第k小的元素。

实现代码的一点解释:
1.upper_bound函数返回的是容器中第一个比中值元素大的元素的迭代器,通过与起始迭代器相减,得到的是容器中小于等于中值元素的元素个数。例如[1,2,4,8],中值为4,那么upper_bound返回的是指向8的迭代器,减去起始迭代器,会得到3,这是等于小于4的元素个数。
2.可能会有这样的疑问:最后得到的结果有没有可能是矩阵中不存在的元素?答案是不会的,要注意程序中循环的结束条件并不是统计个数等于k,而是l < r,也就意味着即便在某一轮循环中,小于等于中值的元素个数刚好是k,我们也会继续循环,这样做的目的是让l跟r逼近矩阵中存在的第k个元素。


代码

我的代码

class Solution {
public:
    int kthSmallest(vector<vector<int>>& matrix, int k) {
        priority_queue<int> kth;

        for (int i = 0; i < matrix.size(); i++) {
            for (auto n: matrix[i]) {
                kth.push(n);
                if (kth.size() > k)
                    kth.pop();
            }
        }

        return kth.top();
    }
};

参考代码1

class Solution { 
public: 
    struct compare 
    { 
        bool operator()(const pair<int,pair<int, int> >& a, const pair<int,pair<int, int> >& b)
        { 
            return a.first>b.first; 
        }
    }; 

    int kthSmallest(vector<vector<int>>& arr, int k)
    { 
        int n=arr.size(),m=arr[0].size();

        priority_queue< pair<int,pair<int, int> >, vector<pair<int, pair<int, int> > >, compare > p;

        for(int i=0;i<n;i++) 
            p.push(make_pair(arr[i][0],make_pair(i,0)));

        int x=k,ans;
        while(x--) {
            int e=p.top().first;
            int i=p.top().second.first;
            int j=p.top().second.second;
            ans=e;
            p.pop();

            if(j!=m-1)
                p.push(make_pair(arr[i][j+1],make_pair(i,j+1)));
        }

        return ans;
    }
};

参考代码2

class Solution {
public:
    int kthSmallest(vector<vector<int>>& matrix, int k) {
        int size = matrix.size(), l = matrix[0][0], r = matrix[size-1][size-1];

        while(l < r) {
            int smaller = 0, m = l+((r-l)>>1);
            cout << l << " " << r  << " " << m << endl;
            for(int i = 0; i < size; ++i)
                smaller += upper_bound(matrix[i].begin(), matrix[i].end(), m)-matrix[i].begin();
            cout << smaller << endl;
            smaller<k? l=m+1 : r=m;
        }
        return r;
    }
};

总结

通过这道堆的题目,我又重温了蛮多关于堆的知识,也学到了以前没有见过的新的函数upper_bound()。那个二分解法着实开阔了我的思维,最喜欢的就是在做题时能够学习到新的知识,这种感觉真好。
这个坑早上就填了,但是晚上才腾出时间写报告,明天争取中午的时候填一个坑并且把解题报告写完,加油加油!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值