378. Kth Smallest Element in a Sorted Matrix。

来源:互联网 发布:移动网络服务商电话 编辑:程序博客网 时间:2024/06/10 19:24

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.


第一个方法就比较简单了,可以将所有的元素都放在一个数组中,然后对这个数组排序,就可以直接拿到对应的k了。

        vector<int> number;        int n = matrix.size();        for (int i=0; i<n; i++)        {            for(int j=0; j<n; j++)            {                number.push_back(matrix[i][j]);            }        }        sort(number.begin(),number.end());        return number[k-1];

这个效率可能就比较低了,这里跑了53ms,所以可以采用二分法,效率可以提高到39ms。

二分法分别从第一个和最后一个向中间进行扫描,并且计算出中间的数值与数组中的进行比较,可以通过upper_bound函数可以计算出这个中间值在这个数组中排多少位,然后得到比中间值小的或者大的数字有多少个,然后与k进行比较,如果比k小则说明中间值太小了,则向后移动开始的位置,反之向前移动最后的位置。

#include <iostream>#include <vector>#include <algorithm>using namespace std;class Solution{public:    int kthSmallest(vector<vector<int>>& matrix, int k)    {        int n = matrix.size();        int startNum = matrix[0][0];//最小的数        int endNum = matrix[n-1][n-1];//最大的数        int midNum;//计算最大值和最小值的数        int cnt = 0;        while (startNum < endNum) {            midNum = (startNum + endNum) / 2;//得到中间的数值            cnt = 0;            cout << midNum << "," <<startNum << "," << endNum << endl;            for(int i=0;i<n;i++) {                cout << "i:" << i << "," << *(upper_bound(matrix[i].begin(), matrix[i].end(), midNum)) << "," << *(matrix[i].begin()) << "," << (upper_bound(matrix[i].begin(), matrix[i].end(), midNum) - matrix[i].begin()) << endl;                cnt += (upper_bound(matrix[i].begin(), matrix[i].end(), midNum) - matrix[i].begin());                cout << "cnt :" << cnt << endl;            }            if(cnt < k) {                startNum = midNum + 1;            } else {                endNum = midNum;            }            cout << endl;        }        cout << endNum;        cout << startNum;        return endNum;        /*vector<int> number;        int n = matrix.size();        for (int i=0; i<n; i++)        {            for(int j=0; j<n; j++)            {                number.push_back(matrix[i][j]);            }        }        sort(number.begin(),number.end());        return number[k-1];*/    }};int main(){    Solution s;    vector<vector<int>> martrix;    vector<int> a1;    vector<int> a2;    vector<int> a3;    a1.push_back(1);    a1.push_back(5);    a1.push_back(9);    a2.push_back(10);    a2.push_back(11);    a2.push_back(13);    a3.push_back(12);    a3.push_back(13);    a3.push_back(15);    martrix.push_back(a1);    martrix.push_back(a2);    martrix.push_back(a3);    s.kthSmallest(martrix,4);}

以上代码运行结果(注意上述代码中求得k为4,而不是8):

这里写图片描述

有关upper_bound的用法可以参考这片文章:http://blog.csdn.net/quack_quack/article/details/48447293

可以从图中看到while总共执行了四次。

第一次:

startNum = 1,endNum = 15.。因为一开始就是从最大和最小向中间进行计算的。
midNum = 8,里面的for循环共执行了三次。每次都是通过upper_bound找到这一排中比midNum小的数值,所以第一排共有两个(cnt的值)。总共也只有两个,此时说明8这个数字在数组中能排到第三位,而我们需要的是第4位。所以我们要找的数值肯定就会在midNum+1和endNum中了。

第二次:

startNum = 9,endNum = 15。
midNum = 12,找到比midNum小的数值有6个。(包括了等于的)这说明midNum在数组中可以排到第六(也可以说是第七,因为正好数组中正好有一个12,算上这个12的话,如果不算并列的话就是第七)。比我们要找的第4位大,所以我们要找的数值肯定就在startNum和midNum中。

第三次:

startNum = 9,endNum = 12.
midNum = 10,找到比midNum小的数值有四个。这说明midNum可以排到第四。这其实就是我们想要得值,但是startNum和endNum还没有重合,所以中间还有其他的可能。所以需要进一步确定。并且最终的值肯定在startNum和midNum中。为什么不是midNum到endNum呢?因为此时的midNum正好等于我们想要的,但是根据代码,如果我们取后面的话我们就会从midNum+1进行计算了。所以我们取前面的也就是startNum到minNum。

第四次:

startNum = 9,endNum = 10。
midNum = 9,此刻找到比midNum小的数值有三个,说明9可以排到第三位,但我们要的是第四位。所以我们要的k必然在midNum+1和endNun中,而此时正好是两个相等。所以就求出我们要的数值。

我的这个介绍感觉有错误的地方,仅供参考。

原创粉丝点击