题目描述:
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
andn
will be in the range [1, 30000]. - The
k
will be in the range [1, m * n]
解题思路:
最开始的想法是:这个题目的标签是二分查找,那能不能先吧乘法表存在数组里,然后排个序再进行二分查找。后来看到m,n的范围太大,如果存数组,leetcode肯定会内存爆掉。然后上网找了代码,理解之后得到了下面的解法:
第K小元素 <=> 小于等于它的元素有K个 => 用二分法去统计小于等于某个元素mid的元素的个数count => 当count=k时,mid即为所求
要点:
因为矩阵里存的是乘法表,所以m*n矩阵里存的元素x的范围为1<=x<=m*n, 但是这个范围内的元素不一定全都在。所以:
1.一定要保证是小于等于关系,才能保证找到的mid是第K小且是矩阵里的元素,所以取high = mid;
2.统计个数,并不需要将整个乘法表还原,而是利用乘法表的性质matrix[i][j](矩阵第i行,第j列的元素)= i*j。mid/i可以求出第i行小于mid的元素个数,但是由于矩阵大小的限制mid/i <= n。
(上述讲解中的变量可能要结合代码看才更好理解,有解释不清的地方欢迎留言~)
代码:
#include<iostream>
using namespace std;
int countNumber(int m, int n, int mid) {
int count = 0;
for (int i = 1; i <= m; i++) {
int temp = mid / i;
if (temp >= n) {
count += n;
} else {
count += temp;
}
}
return count;
}
int findKthNumber(int m, int n, int k) {
int low = 1, high = m * n;
while (low < high) {
int mid = (low + high) / 2;
int count = countNumber(m, n, mid);
if (count < k) {
low = mid + 1;
} else {
high = mid;
}
}
return high;
}
int main() {
int m, n, k;
cin >> m;
cin >> n;
cin >> k;
cout << "The " << k << "th smallest number is " << findKthNumber(m, n, k) << endl;
return 0;
}
Dev C++上运行截图(leetcode上也是测试通过的):
(1)
(2)