leetcode 378. 有序矩阵中第K小的元素

问题描述

给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。
请注意,它是排序后的第 k 小元素,而不是第 k 个不同的元素。

 

示例:

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

返回 13。
 

提示:
你可以假设 k 的值永远是有效的,1 ≤ k ≤ n2 。

问题分析

由于是有序矩阵,那么左上角的数字一定是最小的,而右下角的数字一定是最大的,所以这个是我们搜索的范围,然后我们算出中间数字middle,由于矩阵中不同行之间的元素并不是严格有序的,所以我们要在每一行都查找一下 middle,举一个简单的例子:

[1 2
12 100]
k = 3
那么刚开始 left = 1, right = 100, mid = 50, 遍历完 cnt = 3,此时 right 更新为 50
此时 left = 1, right = 50, mid = 25, 遍历完之后 cnt = 3, 此时 right 更新为 25
此时 left = 1, right = 25, mid = 13, 遍历完之后 cnt = 3, 此时 right 更新为 13
此时 left = 1, right = 13, mid = 7, 遍历完之后 cnt = 2, 此时 left 更新为8
此时 left = 8, right = 13, mid = 10, 遍历完之后 cnt = 2, 此时 left 更新为 11
此时 left = 11, right = 12, mid = 11, 遍历完之后 cnt = 2, 此时 left 更新为 12
循环结束,left 和 right 均为 12,任意返回一个即可。

代码

class Solution {
public:
    int kthSmallest(vector<vector<int>>& matrix, int k) {
        if(!k)return matrix[0][0];
        //以下至少2*2矩阵了
        int m = matrix.size();
        int left = matrix[0][0],right = matrix[m-1][m-1],middle,count;
        while(left < right)
        {
            middle = left + (right-left)/2;
            count = count_less_equal(matrix,middle);
            if(count < k)
                left = middle+1;
            else    
                right = middle;
        }
        return right;
    }
    int count_less_equal(vector<vector<int>>& matrix,int target)
    {
        int n = matrix.size(),i = n-1,j = 0;//从左下角的元素开始搜索
        int ans = 0;
        while(i >= 0 && j < n)
        {
            if(matrix[i][j] <= target)
            {//如果当前值比目标值小,说明当前列该元素及以上的元素都比target小,这些元素有i+1个,之后可以向右搜索了
                ans += i+1;
                ++j;
            }
            else{
                //如果当前值比目标值大,则需要从该列向上搜索
                --i;
            }
        }
        return ans;
    }
};

结果

执行用时:56 ms, 在所有 C++ 提交中击败了88.52%的用户
内存消耗:12 MB, 在所有 C++ 提交中击败了20.00%的用户

代码2

class Solution {
public:
    int kthSmallest(vector<vector<int>>& matrix, int k) {
        if(!k)return matrix[0][0];
        //以下至少2*2矩阵了
        int m = matrix.size(), n = matrix[0].size();
        priority_queue<int> q;
        for(int i = 0; i < m; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                q.emplace(matrix[i][j]);
                if(q.size() > k)
                    q.pop();
            }
        }
        return q.top();
    }
};

结果

执行用时:152 ms, 在所有 C++ 提交中击败了16.92%的用户
内存消耗:13.5 MB, 在所有 C++ 提交中击败了20.00%的用户
posted @ 2020-07-02 11:14  曲径通霄  阅读(136)  评论(0编辑  收藏  举报