題目:
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]
本題就是尋找乘法表中第k小的數,但是這個題目其實跟之前一道求一個行和列都是增序排列的矩陣中找第k小的元素是一樣的,不明白爲什麼這裏又放了出來。不過這道題目相對來說更加簡單,因爲元素排列更加有規律,甚至是一個對角矩陣的形式。我們可以下使用之前一道題目的思路來解決,就是對第一個元素和最後一個元素進行二叉搜索,然後每個元素判斷每一行有幾個比其小的值並求和,看是否==k即可。代碼如下所示:
public static int findKthNumber(int m, int n, int k) {
int left=1, right = m*n, mid;
while(left <= right){
mid = left + (right-left)/2;
int count=0, j=n;
for(int i=1; i<=m; i++){
//遍歷每一行
//看一行中有幾個元素小於當前值
while(j >= 1 && i*j > mid) j--;
//求和
count += j;
}
if(count < k)left = mid+1;
else right = mid - 1;
}
return left;
}
此外,考慮到當前題目的特殊性我們還可以使用下面這個方法來解決,但是效率沒有上面好,只可以擊敗85%的用戶:
public int findKthNumber1(int m, int n, int k) {
int low = 1, high = m * n;
while (low <= high) {
int mid = low + (high - low) / 2;
int count = helper(m, n, mid);
if (count >= k) high = mid - 1;
else low = mid + 1;
}
return low;
}
private int helper(int m, int n, int num) {
int count = 0;
for (int i = 1; i <= m; i++) {
count += Math.min(num / i, n);
}
return count;
}