【leetcode/二分】有序矩陣的第k小元素(虛擬數組+夾逼二分)

問題描述:

給定一個 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的值。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章