问题描述:
几乎每一个人都用 乘法表。但是你能在乘法表中快速找到第k小的数字吗?
给定高度m 、宽度n 的一张 m * n的乘法表,以及正整数k,你需要返回表中第k 小的数字。
代码语言:javascript复制例 1:
输入: m = 3, n = 3, k = 5
输出: 3
解释:
乘法表:
1 2 3
2 4 6
3 6 9
第5小的数字是 3 (1, 2, 2, 3, 3).
例 2:
输入: m = 2, n = 3, k = 6
输出: 6
解释:
乘法表:
1 2 3
2 4 6
第6小的数字是 6 (1, 2, 2, 3, 4, 6).
注意:
m 和 n 的范围在 [1, 30000] 之间。
k 的范围在 [1, m * n] 之间。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/kth-smallest-number-in-multiplication-table
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解决方案
由于m和n范围为3e4,m*n为9e8,因此将所有数字得到排序的算法是不满足要求的。
对于该问题假设我们已经知道了一个数记做target,target的上界为m * n,下界为1,只需统计乘法表中不大于target元素的数目与k相比即可。随着target值的增长得到的元素数目亦是增长,因此可以使用二分查找的方式。该问题就可以转化为找到元素数目大于等于k的最小target。
给定target统计乘法表中不大于target的元素数目,从乘法表的右上角开始,若当前值大于target,左移;否则加上以当前位置结尾的横向序列长度并下移。
代码语言:javascript复制class Solution {
public int findKthNumber(int m, int n, int k) {
int right = m * n;
int left = 1;
// 找到满足条件的最小的 这是由于某个乘法表中不存在的数亦会使得count = k
while(left < right){
int mid = left (right - left) / 2;
if(count(m, n, mid) < k){
left = mid 1;
}else{
right = mid;
}
}
return left;
}
// 找到小于等于target的元素数目
public int count(int m, int n, int target){
int i = 1;
int j = n;
int ans = 0;
while(i <= m && j >= 1){
if(i * j > target){
j--;
}else{
ans = j;
i ;
}
}
return ans;
}
}
二分的时间复杂度为O(log(m * n)),统计的时间复杂度为O(m n)总体时间复杂度为O((m n )* log(m * n));