668. Kth Smallest Number in Multiplication Table
问题描述:
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]
解题思路:
我一看这题,跟另外一道题有点类似啊(378. Kth Smallest Element in a Sorted Matrix),当时喜滋滋的就开始做。
利用了矩阵本身的性质(每一行每一列都有序,但是列与列,行与行并没有很有序)并且与priority_queue(重写比较器使之成为最小堆)结合使用。
给的例子都过了,然后我喜滋滋的点了submit :)
没过。
leetcode怎么会有一毛一样的题呢?naive :)
乘法表比起有序矩阵来说,性质更加特殊:每一行都是一个等差数列。
我们可以使用binary search二分搜索来解答。
左边界为1;右边界为 m*n
算得中间值,然后来看比中间值小的数字在乘法表里有多少?
多于k的话,将右边界左移。
小于k的话,将左边界右移。
参考了GrandYang(不用看就能写对了已经,大佬就是我的答案) 的解法。
重点理解算比中间值小的数字的个数的过程:
- 将mid 于 i*n比较, i是行数,i belongs to [1, m], i*n是本行最大的数字
- 若mid > i*n 说明 mid 比这一行都大,cnt(计数器) += n
- 若mid <= i*n 说明mid 处于这一行中。cnt += mid / i, 因为i是一个因数,在这一行内分别于1.... n 相乘,所以可以通过这种方式计算 子这一行里小于mid的个数。
这道题告诉我:
- 遇到类似原题不要太开心,要把它当新题做。
- 要仔细分析输入的性质并且加以利用。
- 人生真的好难
代码:
class Solution { public: int findKthNumber(int m, int n, int k) { int l = 1, r = m*n; while(l < r){ int mid = l/2 + r/2; //calculate current number of element less than mid position; int cnt = 0; for(int i = 1; i <= m; ++i){ cnt += (mid > n*i) ? n : mid/i; } if (cnt < k) l = mid + 1; else r = mid; } return r; } };
时间复杂度 O(log n), 空间O(1)