class Solution:
def findKthNumber(self, m: int, n: int, k: int) -> int:
def countLessEqual(x):
count = 0
for i in range(1, m+1):
count += min(x // i, n)
return count
left, right = 1, m * n
while left < right:
mid = (left + right) // 2
if countLessEqual(mid) < k:
left = mid + 1
else:
right = mid
return left
class Solution {
public:
int findKthNumber(int m, int n, int k) {
auto countLessEqual = [&](int x) {
int count = 0;
for (int i = 1; i <= m; ++i) {
count += std::min(x / i, n);
}
return count;
};
int left = 1, right = m * n;
while (left < right) {
int mid = left + (right - left) / 2;
if (countLessEqual(mid) < k)
left = mid + 1;
else
right = mid;
}
return left;
}
};
class Solution {
public int findKthNumber(int m, int n, int k) {
int left = 1, right = m * n;
while (left < right) {
int mid = left + (right - left) / 2;
int count = 0;
for (int i = 1; i <= m; ++i) {
count += Math.min(mid / i, n);
}
if (count < k) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
}
var findKthNumber = function(m, n, k) {
function countLessEqual(x) {
let count = 0;
for (let i = 1; i <= m; ++i) {
count += Math.min(Math.floor(x / i), n);
}
return count;
}
let left = 1, right = m * n;
while (left < right) {
let mid = Math.floor((left + right) / 2);
if (countLessEqual(mid) < k) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
};
Given two integers m
and n
, representing the number of rows and columns in a multiplication table (where the value at cell (i, j)
is i * j
), and an integer k
, your task is to find the k
th smallest number in this m x n
multiplication table.
For example, if m = 3
, n = 3
, and k = 5
, the multiplication table is:
1 2 3 2 4 6 3 6 9
The sorted order of elements is [1, 2, 2, 3, 3, 4, 6, 6, 9], so the 5th smallest is 3.
At first glance, the problem seems to suggest building the entire multiplication table, sorting all its elements, and then picking the k
th smallest. This brute-force approach is simple but inefficient for large tables (since m
and n
can be up to 30,000). The memory and time required to hold and sort the whole table would be impractical.
Instead, notice that the multiplication table is sorted row-wise and column-wise, but not globally. The key insight is that for any number x
, we can efficiently count how many numbers in the table are less than or equal to x
(by iterating through rows and counting for each row). This allows us to use a binary search approach: we can search for the smallest number such that at least k
numbers in the table are less than or equal to it.
This approach avoids building and sorting the entire table, and instead leverages properties of the multiplication table to count efficiently.
We use a binary search to find the k
th smallest number in the multiplication table.
m * n
(m x n).x
, for each row i
, the number of elements in that row ≤ x
is min(x // i, n)
.x
.k
, the answer must be larger, so move the left boundary up.k
, the answer could be mid or smaller, so move the right boundary down.k
numbers are ≤ it; this is our answer.This approach is efficient because counting is O(m) per binary search step, and the search space is up to m*n.
Let's walk through the example with m = 3
, n = 3
, k = 5
.
m * n
elements and sort them.The key insight to efficiently solve the "Kth Smallest Number in Multiplication Table" problem is to use binary search over the value range of the table, leveraging the ability to count how many numbers are less than or equal to a candidate value without generating the table. This approach is elegant, avoids unnecessary computation and memory usage, and is scalable to very large tables. By focusing on counting and binary search, we transform a seemingly brute-force problem into an efficient solution.