668. 乘法表中第k小的数
几乎每一个人都用 乘法表。但是你能在乘法表中快速找到第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).
例 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] 之间。、
思路:上来想直接暴力一下,先把乘法表构建出来,然后做个排序,返回第k小的值,结果发现超出内存限制。所以看了一下某位大佬的解答,大概思路就是需要找出一定规律,快速判断乘法表每一行小于等于某个数的个数,然后把它们相加起来,通过二分法来不断提供限定集合内的数,然后就判断是否满足条件,最后返回的就是第k小的数
具体可以看:负雪明烛的解答
我的暴力解法
class Solution {
public int findKthNumber(int m, int n, int k) {
int[][] table = new int[m][n];
int[] arr = new int[m*n];
int index = 0;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
table[i][j] = (i+1)*(j+1);
arr[index++] = table[i][j];
}
}
Arrays.sort(arr);
return arr[k-1];
}
}
正确解法
class Solution {
public int findKthNumber(int m, int n, int k) {
int left = 1;
int right = m*n;
//二分搜索
while(left<right){
int mid = left + (right-left)/2;
if(count(m,n,mid)>=k){
right = mid;
}
else{
left = mid + 1;
}
}
return left;
}
public int count(int m,int n,int num){
int res = 0;
for(int i=1;i<=m;i++){ //每一行满足<=num的个数相加
res += Math.min(num/i,n);
}
return res;
}
}