Nearly everyone has used the Multiplication Table. The multiplication table of size m x n
is an integer matrix mat
where mat[i][j] == i * j
(1-indexed).
Given three integers m
, n
, and k
, return the kth
smallest element in the m x n
multiplication table.
For example:
Consider a multiplication table where m = 3, and n = 3. The table would look like this:
1 2 3
2 4 6
3 6 9
If k = 5, the 5th smallest number in the table is 3.
As another example:
Consider a multiplication table where m = 2, and n = 3. The table would look like this:
1 2 3
2 4 6
If k = 6, the 6th smallest number in the table is 6.
Can you efficiently determine the kth smallest element without explicitly constructing the entire multiplication table?
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The problem is about finding a specific number within a multiplication table. The brute force approach simply generates all the numbers in the multiplication table and then sorts them to find the desired one.
Here's how the algorithm would work step-by-step:
def find_kth_number_brute_force(row_size, column_size, k_value):
multiplication_table = []
# Generate the multiplication table.
for row_index in range(1, row_size + 1):
for column_index in range(1, column_size + 1):
product = row_index * column_index
multiplication_table.append(product)
# Sorting is necessary to find the kth smallest element.
multiplication_table.sort()
# Return the kth smallest number.
return multiplication_table[k_value - 1]
The most efficient way to find the kth smallest number is to use a method similar to searching in a sorted list, but adapted for the multiplication table. Instead of checking every number, we use a guessing strategy to narrow down the possibilities.
Here's how the algorithm would work step-by-step:
def findKthNumber(multiplication_table_height, multiplication_table_width, kth_value):
left_value = 1
right_value = multiplication_table_height * multiplication_table_width
while left_value < right_value:
middle_value = left_value + (right_value - left_value) // 2
count = 0
for i in range(1, multiplication_table_height + 1):
count += min(middle_value // i, multiplication_table_width)
# If count is less than kth_value, adjust search.
if count < kth_value:
left_value = middle_value + 1
else:
# If count is >= kth_value, adjust search.
right_value = middle_value
return left_value
Case | How to Handle |
---|---|
m or n is zero | Return 0 immediately as a zero-sized table contains no elements. |
k is zero or negative | Return an error or throw an exception as the kth smallest element is not defined for non-positive k. |
k is greater than m * n | Return the largest element in the table (m * n) since k exceeds the number of elements. |
m or n is 1 | The multiplication table collapses to a single row or column, simplifying the search to finding the kth smallest in a linear sequence. |
Large m and n values (close to integer limits) | Potential integer overflow during calculations (m * n) should be handled by using a 64-bit integer or checking limits. |
k is close to 1 | Binary search should efficiently converge to the correct element near the start of the sorted sequence. |
k is close to m * n | Binary search should efficiently converge to the correct element near the end of the sorted sequence. |
Multiplication table contains duplicate values clustered together | The binary search and counting function within should still function correctly because it counts numbers less than or equal, handling duplicates naturally. |