Leetcode_二分 378.有序矩阵中第K小的元素+668.乘法表中第k小的数

目录

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

668. 乘法表中第k小的数 H


 

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

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

示例:

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

返回 13。

思路一:堆

class Solution {
public:
    int kthSmallest(vector<vector<int>>& matrix, int k) {
        priority_queue<int> pq;
        for (int i = 0; i < matrix.size(); ++i) {
            for (int j = 0; j < matrix[0].size(); ++j) {
                pq.push(matrix[i][j]);
                if (pq.size() > k) pq.pop();
            }
        }
        return pq.top();
    }
};

思路二:二分法   时间复杂度:O(nlgn*lgX),其中X为最大值和最小值的差值 
矩阵最左上角为最小值,最右下角为最大值,我们在此范围内进行二分搜索,取中间数mid,然后在每行中查找mid,

这里使用upper_bound,在每行查找第一个大于mid的元素,

如果目标数比该行的尾元素大,则upper_bound返回该行元素个数,

如果目标数比改行第一个元素小,则uppper_bound返回0,

遍历完所有行可以确定mid是第几小的数,然后与k进行比较,进行二分查找,left和right最终相等,会变为数组中第k小的数。

class Solution {
public:
    int kthSmallest(vector<vector<int>>& matrix, int k) {
        int left = matrix[0][0], right = matrix.back().back();
        while (left < right) {
            int mid = left + (right - left) / 2, cnt = 0;
            for (int i = 0; i < matrix.size(); ++i) {
                cnt += upper_bound(matrix[i].begin(), matrix[i].end(), mid) - matrix[i].begin();
            }
            if (cnt < k) left = mid + 1;
            else right = mid;
        }
        return left;
    }
};

思路二:优化  时间复杂度:O(nlgX)

因为:每行和每列元素均按升序排序 , 

class Solution {
public:
    int kthSmallest(vector<vector<int>>& matrix, int k) {
        int left = matrix[0][0], right = matrix.back().back();
        while (left < right) {
            int mid = left + (right - left) / 2;
            int cnt = search_less_equal(matrix, mid);
            if (cnt < k) left = mid + 1;
            else right = mid;
        }
        return left;
    }

    int search_less_equal(vector<vector<int>> &matrix, int target) {  //O(n)
        int n = matrix.size(), i = n - 1, j = 0, res = 0;
        while (i >= 0 && j < n) {
            if (matrix[i][j] <= target) {
                res += i + 1;
                ++j;
            } else {
                --i;
            }
        }
        return res;
    }
};

 

668. 乘法表中第k小的数 H

几乎每一个人都用 乘法表。但是你能在乘法表中快速找到第k小的数字吗?

给定高度m 、宽度n 的一张 m * n的乘法表,以及正整数k,你需要返回表中第k 小的数字。

例 1:

输入: m = 3, n = 3, k = 5
输出: 3
解释: 
乘法表:
1    2    3
2    4    6
3    6    9

第5小的数字是 3 (1, 2, 2, 3, 3).    O(m*logmn)

class Solution {
public:
   int len(int m, int n, int x){
	int cnt=0;
	for(int i=1;i<=m;i++){
		cnt+=min(n,x/i);
	}
	return cnt;
}

int findKthNumber(int m, int n, int k) {
	int l=1;
	int r=m*n+1;
	while(l<r){
		int x=l+(r-l)/2;
		if( len(m,n,x)>=k ) r=x;
		else  l=x+1;
	}
	return l;
}
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值