题目:
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.
Example 1:
Input: m = 3, n = 3, k = 5
Output:
Explanation:
The Multiplication Table:
1 2 3
2 4 6
3 6 9
The 5-th smallest number is 3 (1, 2, 2, 3, 3).
Example 2:
Input: m = 2, n = 3, k = 6
Output:
Explanation:
The Multiplication Table:
1 2 3
2 4 6
The 6-th smallest number is 6 (1, 2, 2, 3, 4, 6).
Note:
The m and n will be in the range [1, 30000].
The k will be in the range [1, m * n]
本题就是寻找乘法表中第k小的数,但是这个题目其实跟之前一道求一个行和列都是增序排列的矩阵中找第k小的元素是一样的,不明白为什么这里又放了出来。不过这道题目相对来说更加简单,因为元素排列更加有规律,甚至是一个对角矩阵的形式。我们可以下使用之前一道题目的思路来解决,就是对第一个元素和最后一个元素进行二叉搜索,然后每个元素判断每一行有几个比其小的值并求和,看是否==k即可。代码如下所示:
public static int findKthNumber(int m, int n, int k) {
int left=1, right = m*n, mid;
while(left <= right){
mid = left + (right-left)/2;
int count=0, j=n;
for(int i=1; i<=m; i++){
//遍历每一行
//看一行中有几个元素小于当前值
while(j >= 1 && i*j > mid) j--;
//求和
count += j;
}
if(count < k)left = mid+1;
else right = mid - 1;
}
return left;
}
此外,考虑到当前题目的特殊性我们还可以使用下面这个方法来解决,但是效率没有上面好,只可以击败85%的用户:
public int findKthNumber1(int m, int n, int k) {
int low = 1, high = m * n;
while (low <= high) {
int mid = low + (high - low) / 2;
int count = helper(m, n, mid);
if (count >= k) high = mid - 1;
else low = mid + 1;
}
return low;
}
private int helper(int m, int n, int num) {
int count = 0;
for (int i = 1; i <= m; i++) {
count += Math.min(num / i, n);
}
return count;
}