問題描述:
給定一個 n x n 矩陣,其中每行和每列元素均按升序排序,找到矩陣中第k小的元素。
請注意,它是排序後的第k小元素,而不是第k個元素。
示例:
matrix = [
[ 1, 5, 9],
[10, 11, 13],
[12, 13, 15]
],
k = 8,
返回 13。
說明:
你可以假設 k 的值永遠是有效的, 1 ≤ k ≤ n2 。
基本思路:
這裏我們引入一個虛擬數組的概念:
我們的二分法並不基於我們現存的數組。我們只是利用我們現存的數組設定left和right.
而我們的mid則是基於我們自己設定的標準,他並不一定在這個數組中。
AC代碼:
class Solution {
public:
int Count(vector<vector<int>> &m, int target) {
int count = 0;
int n = m.size();
// 利用基本已經排好序的矩陣的性質來統計數據
for (int i = 0; i < n; ++i) {
int j = n - 1;
while (j >= 0) {
if (m[j][i] <= target) {
count += j + 1;
break;
} else {
--j;
}
}
}
return count;
}
int kthSmallest(vector<vector<int>>& matrix, int k) {
int n = matrix.size(); // 這是一個方陣, 所以只要求一個維度就行
int left = matrix[0][0];
int right = matrix[n - 1][n - 1];
// 這裏的二分並不是直接基於我們的數據結構
// 而是我們虛擬化了一個數組
int mid = left; // 防止left和right相等的時候,進不去循環
while (left < right) {
mid = left + (right - left) / 2; // mid不再是索引,而是實打實的元素值
int count = Count(matrix, mid); // 在數組中尋找比mid小的所有元素個數
// 夾逼法求得符合要求的元素
if (count >= k) right = mid; // 說明mid過大
else left = mid + 1;
}
return left; // 注意這裏是返回left或者right而不是返回mid
}
};
其它經驗:
注意夾逼二分的時候返回的是left和right的值,而不是mid的值。