# 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 and n will be in the range [1, 30000].
The k will be in the range [1, m * n]
Solution 1
Firstly, use a map to store different numbers and their occurrences in the multiplication table, then get the Kth smallest number from the map (Time Limit Exceeded)
// C++
int findKthNumber(int m, int n, int k) {
if (m == 0 || n == 0 || k > m * n) {
return -1;
}
unordered_map<int, int> numDict;
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
int curNum = i * j;
if (numDict.count(curNum) <= 0) {
numDict[curNum] = 0;
}
++numDict[curNum];
}
}
int count = 0;
// The Kth smallest number must be less than or equal to k
for (int i = 1; i <= k; ++i)
{
count += numDict[i];
if (count >= k) {
return i;
}
}
}
Time Complexity: O(m*n + k)
Space Complexity: O(m*n)
Solution 2
Refer to
[1] http://www.cnblogs.com/shuashuashua/p/7500858.html
[2] http://blog.csdn.net/xiaocong1990/article/details/77651714
We can enumerate every number from 1 to m*n, count the number of numbers less than or equal to this number, return the first number with k numbers less than or equal to it.
Inspired by “Basic idea could be same as the Kth smallest number in sorted matrix” from [1]. We can use binary search to reduce the time complexity (not necessary to enumerate every number).
such as m = n = 3, k = 5
1 2 3
2 4 6
3 6 9
start = 1, end = m * n, mid = start + (end - start)
if count(less than or equal to mid) < k: start = mid + 1 (the Kth smallest number can’t be in range [start, mid])
if count(less than or equal to mid) >= k: end = mid (the Kth smallest number must be in range [start, mid])
repeat this process, until start = end, that is, find the kth smallest number
Another problem: how to compute count(less than or equal to mid) ?
mid divides i=1…m, represent the number less than or equal to mid in row i. Of course, the number must be less than or equal to n, so
count(less than or equal to mid) += (mid / i >= n) ? n : mid / i, i = 1…m
// C++
int findKthNumber(int m, int n, int k) {
if (m <= 0 || n <= 0 || k > m * n) {
return -1;
}
int start = 1;
int end = m * n;
while (start < end) {
int mid = start + (end - start) / 2;
// count all nums less than or equal to mid
int cnt = 0;
for (int i = 1; i <= m; ++i) {
cnt += (mid / i >= n) ? n : mid / i;
}
if (cnt < k) {
start = mid + 1;
} else {
end = mid;
}
}
return start;
}
""" python """
def findKthNumber(self, m, n, k):
"""
:type m: int
:type n: int
:type k: int
:rtype: int
"""
if m <= 0 or n <= 0 or k > m * n:
return -1
start = 1
end = m * n
while start < end:
mid = start + (end - start) // 2
cnt = 0
for i in range(1, m + 1):
max_cnt = mid // i
if max_cnt <= n:
cnt += max_cnt
else:
cnt += n
if cnt < k:
start = mid + 1
""" this condition is wrong
Because if a count (less than or equal to mid) > k, it still maybe the Kth smallest number (such as 1 2 3; 2 4 6, 3 is the 4th smallest number, but count(<=3) = 5 > 4)
"""
# elif cnt > k:
# end = mid - 1
else:
end = mid
return start
Time Complexity: O(m*log(m*n))
Space Complexity: O(1)