1. 程式人生 > >【LeetCode & 劍指offer刷題】矩陣題3:Kth Smallest Element in a Sorted Matrix

【LeetCode & 劍指offer刷題】矩陣題3:Kth Smallest Element in a Sorted Matrix

【LeetCode & 劍指offer 刷題筆記】目錄(持續更新中...)

Kth Smallest Element in a Sorted Matrix

Given a   n   x   n   matrix where each of the rows and columns are sorted in ascending order, find the kth smallest element in the matrix.
Note that it is the kth smallest element in the sorted order, not the kth distinct element. Example: matrix = [ [ 1, 5, 9], [10, 11, 13], [12, 13, 15] ], k = 8,
  return 13. Note:   You may assume k is always valid, 1 ≤ k ≤ n 2 .
C++   /*  題目說為 
n x n matrix,行列均有序,找出第k小的元素
方法一:二分查詢法 整體二分查詢,在每行二分查詢,統計每行小於等於目標數的個數 O(logm * nlogn ) m為元素個數,行數和列數均為n, 平均logm次計算mid(while語句),每行進行二分查詢,時間複雜度為O(nlogn)   注意:一般的二分查詢left和right為索引,而這裡left,right為元素值,準確來說logm中m應指最大數和最小數的差值。 (感覺演算法不是最優的,有冗餘的地方,還是用索引的二分查詢法會好一點,mid換算成行列數即可,參見: 4 有序矩陣中的查詢(系列 74. Search a 2D Matrix )例: [1 2 12 100] k = 3 那麼剛開始left = 1, right = 100, mid = 50, 遍歷完 cnt = 3,此時right更新為50 此時left = 1, right = 50, mid = 25, 遍歷完之後 cnt = 3, 此時right更新為25 此時left = 1, right = 25, mid = 13, 遍歷完之後 cnt = 3, 此時right更新為13 此時left = 1, right = 13, mid = 7, 遍歷完之後 cnt = 2, 此時left更新為8 此時left = 8, right = 13, mid = 10, 遍歷完之後 cnt = 2, 此時left更新為11 此時left = 11, right = 12, mid = 11, 遍歷完之後 cnt = 2, 此時left更新為12 迴圈結束,left和right均為12,任意返回一個即可。 */ class Solution { public :      int kthSmallest ( vector < vector < int >>& matrix , int k )      {          int n = matrix . size ();          int left = matrix[0][0], right = matrix[n - 1][n - 1];          int mid = 0 ;          while ( left < right ) //掃描整個矩陣,這裡left,right為值,一般的二分查詢為索引          {             mid = left + ( right - left )/ 2 ;              int count = 0 ;              for ( int i = 0 ; i < n ; i ++) //掃描每行              {                  int pos = upper_bound ( matrix [ i ]. begin (), matrix [ i ]. end (), mid ) - matrix [ i ]. begin (); //用二分查詢查詢第一個大於目標數的位置,可統計該行中比目標數小的數量                 count += pos ;              }              if ( count < k ) //這裡賦left = mid+1和right = mid不是太懂                  left = mid + 1 //比k小時,left往中間移,增大新mid,增大count              else                 right = mid ;  //比k大或者等於時,right往中間移          //退出迴圈時left = right,移動至第k小的元素處          return left ;      } };     /* 方法二:二分查詢 + 直接統計法(利用行列有序性) 我們並不用對每一行都做二分搜尋法,我們注意到每列也是有序的,我們可以利用這個性質,依次統計每一列中小於等於目標值的元素數量 1.從陣列的左下角開始查詢(i = n-1,j = 0),掃描至矩陣上邊界或者右邊界,共執行次數最多2n 2.如果a[i][j] <= target,因為當前元素以上的元素均比目標值小,cnt += i+1,繼續下一列的判斷(j++); 3.如果a[i][j] > target,則向上移一位(i--),這樣我們也能算出cnt的值。 複雜度為 O(logm * n) */ class Solution { public :     int kthSmallest ( vector < vector < int >>& matrix , int k )      {         int left = matrix [ 0 ][ 0 ], right = matrix . back (). back ();         while ( left < right )          {             int mid = left + ( right - left ) / 2 ;             int cnt = search_less_equal ( matrix , mid );                          if ( cnt < k )                   left = mid + 1 ;             else                   right = mid ;         }         return left ;     }     int search_less_equal ( vector < vector < int >>& matrix , int target )      {         int n = matrix . size (), i = n - 1, j = 0 , res = 0 ; //從矩陣左下角開始掃描         while ( i >= 0 && j <= n - 1 ) //如果行或列超出邊界就退出迴圈          {              //統計每列小於等於目標值的數量             if ( matrix [ i ][ j ] <= target ) //當前元素小於或等於目標值              {                 res += i + 1 ; //統計每列小於等於目標值的數量                 j ++; //掃描下一列             } else //當前元素比目標值大              {                 i --; //掃描上一行             }         }         return res ;     } };