Kth Smallest Number in Multiplication Table
Binary search the value; count how many cells of the m-by-n multiplication table are at most mid via a per-row division.
4 min read
binary-search matrix parametric-search
Problem#
In an m x n multiplication table (cell (i, j) contains i * j, 1-indexed), return the k-th smallest value.
Examples#
m = 3, n = 3, k = 5→3m = 2, n = 3, k = 6→6
Constraints#
1 <= m, n <= 3 * 10^4,1 <= k <= m * n.
Approach#
The count of cells with value at most v is sum over i in 1..m of min(v / i, n). This count is monotone in v. Binary search v over [1, m*n]; pick the smallest v whose count is at least k.
Solution#
class Solution {public: int findKthNumber(int m, int n, int k) { auto countLE = [&](int v) { int total = 0; for (int i = 1; i <= m; ++i) total += min(v / i, n); return total; }; int lo = 1, hi = m * n; while (lo < hi) { int mid = lo + (hi - lo) / 2; if (countLE(mid) < k) lo = mid + 1; else hi = mid; } return lo; }};func findKthNumber(m int, n int, k int) int { countLE := func(v int) int { total := 0 for i := 1; i <= m; i++ { q := v / i if q > n { q = n } total += q } return total } lo, hi := 1, m*n for lo < hi { mid := lo + (hi-lo)/2 if countLE(mid) < k { lo = mid + 1 } else { hi = mid } } return lo}class Solution: def findKthNumber(self, m: int, n: int, k: int) -> int: def count_le(v: int) -> int: total = 0 for i in range(1, m + 1): total += min(v // i, n) return total
lo, hi = 1, m * n while lo < hi: mid = lo + (hi - lo) // 2 if count_le(mid) < k: lo = mid + 1 else: hi = mid return lofunction findKthNumber(m, n, k) { const countLE = (v) => { let total = 0; for (let i = 1; i <= m; i++) total += Math.min(Math.floor(v / i), n); return total; }; let lo = 1, hi = m * n; while (lo < hi) { const mid = lo + Math.floor((hi - lo) / 2); if (countLE(mid) < k) lo = mid + 1; else hi = mid; } return lo;}class Solution { public int findKthNumber(int m, int n, int k) { int lo = 1, hi = m * n; while (lo < hi) { int mid = lo + (hi - lo) / 2; if (countLE(mid, m, n) < k) lo = mid + 1; else hi = mid; } return lo; }
private int countLE(int v, int m, int n) { int total = 0; for (int i = 1; i <= m; i++) total += Math.min(v / i, n); return total; }}function findKthNumber(m: number, n: number, k: number): number { const countLE = (v: number): number => { let total = 0; for (let i = 1; i <= m; i++) total += Math.min(Math.floor(v / i), n); return total; }; let lo = 1, hi = m * n; while (lo < hi) { const mid = lo + Math.floor((hi - lo) / 2); if (countLE(mid) < k) lo = mid + 1; else hi = mid; } return lo;}Editorial#
Row i contains values i, 2i, ..., n*i; the count at or below v is min(v / i, n). Summing across rows gives the rank of v. Binary search finds the smallest v whose rank is at least k — that’s the k-th smallest value.
Complexity#
- Time: O(m log(m*n)).
- Space: O(1).
Concept revision#
Related#