问题描述
Nearly every one have used the Multiplication Table. But could you find out the k-th smallest number quickly from the multiplication table?
Given the height m and the length n of a m * n Multiplication Table, and a positive integer k, you need to return the k-th smallest number in this table.
请你一个m * n
的乘法表,请计算第k
个小的元素。
举个例子:
解法1
先来看下乘法表每个元素的组成结构:
我们可以使用二分法,从上到下依次统计小于等于k
元素的数量:
再来看下使用二分时满足的性质:
来看下实现:
class Solution {
private int count(int m, int n, int mid){
int cnt = 0;
for (int i = 1; i <= m; i++){
cnt += Math.min(mid / i, n);
}
return cnt;
}
public int findKthNumber(int m, int n, int k) {
int l = 1, r = m * n;
while (l < r){
int mid = l + r >>> 1;
if (count(m, n, mid) >= k) r = mid;
else l = mid + 1;
}
return r;
}
}
Enjoy it !
疑问
当我们使用这条性质时,m = 45, n = 12, k = 471
,输出结果为311
,正确结果为312
class Solution {
private int count(int m, int n, int mid){
int cnt = 0;
for (int i = 1; i <= m; i++){
cnt += Math.min(mid / i, n);
}
return cnt;
}
public int findKthNumber(int m, int n, int k) {
int l = 1, r = m * n;
while (l < r){
int mid = l + r + 1 >>> 1;
if (count(m, n, mid) <= k) l = mid;
else r = mid - 1;
}
return r;
}
}
若您知道如何调整,还请留言指点一下~
因为矩阵展开成一维数组后,相邻两个数的值之间不是连续的,而二分搜索的是区间[1,m*n]的连续值。所以如果二分搜的是右边界,那么矩阵展开后相邻两个数之间的数其实也是满足条件的(因为无法用乘积表示所以这些数不在矩阵中,比如相邻两个数之间的质数),此时这些数可能会作为上界被搜到;而如果搜的是左边界,才能搜出满足条件的数的下界,才能够取到矩阵展开后的一维数组的某个数上。
我也有同样的疑惑,我是这样理解的,小于等于mid的个数是大于等于k的(因为可能有重复的数) ==> 就是找到小于等于mid的个数大于等于K的最小值 cnt(mid) >= k ==> 右区间的边界值。
假如nm都是3,则一维数组就是1,2,2,3,3,4,6,6,9。当k=2的时候
cnt(9) = 9 >= 2
cnt(2) = 3 >= 2 (答案)
cnt(1) = 1
需要注意求cnt的函数是 矩阵中最后一次出现位置
我也不知道啊