Leetcode--378. 有序矩陣中第K小的元素
給定一個 n x n 矩陣,其中每行和每列元素均按升序排序,找到矩陣中第k小的元素。
請注意,它是排序後的第k小元素,而不是第k個元素。
示例:
matrix = [
[ 1, 5, 9],
[10, 11, 13],
[12, 13, 15]
],
k = 8,
返回 13。
說明:
你可以假設 k 的值永遠是有效的, 1 ≤ k ≤ n2 。
--------------------------------------------------------------------------------------------------------------------------------------------------
我通過這道題了解了,二分查詢的演算法怎麼寫,之前只在書上見過,並沒有實際的應用過,今天是第一次看到怎麼應用在題目中。。。。。。。
由於每行每列的方向都是遞增的。 這也是一個二分寫法的題目的一個特點,表內元素必須有序。
AC:
class Solution {
public:
bool fun(long long midd,vector<vector<int>>& matrix, long long k,long long n)
{
int sum=0;
for (int i=0;i<n;i++)
{
int l=0;
int r=n-1;
int ans=0; // ans是用來記錄每行中
while(l<=r) //閉區間不問空的條件是左界不大於右界,即(l<=r),如果是左閉右開區間,不空的條件是l<r
{
int mid=(l+r)/2;
if (matrix[i][mid]<midd)
{
ans=mid+1; //因為每行元素都是遞增的,那麼mid+1就表示在這一行中比midd小的元素的數量。
l=mid+1;
}
else
r=mid-1;
}
sum=sum+ans;
}
return k>sum; //如果sum<k(即midd的排名比k小),說明midd猜的比較小。在kith那個函式中的左邊界就要mid+1(即變 // 大)因為在矩陣中,越往右下角越大。
}
int kthSmallest(vector<vector<int>>& matrix, int k) {
long long n=matrix.size();
long long l=matrix[0][0];
long long r=matrix[n-1][n-1];
long long ans=0;
while(l<=r)
{
long long mid=(l+r)/2;
if (fun(mid,matrix,k,n)) //mid與sum是一個正相關
{
ans=mid;
l=mid+1;
}
else
{
r=mid-1;
}
}
return (int)ans;
}
};
如果用STL中的庫函式的話,那麼可以寫成
- 兩個迭代器相減代表的是兩個之間的距離。
- lower_bound() 返回一個迭代器,指向第一個不小於目標val的元素。
- upper_bound()返回一個迭代器,指向第一個大於目標val的元素。
AC:
class Solution {
public:
int kthSmallest(vector<vector<int>>& matrix, int k) {
vector<vector<int>> mm=matrix; //偷懶的寫法,matrix覺得寫的麻煩。
int n=mm.size();
long long l=mm[0][0];
long long r=mm[n-1][n-1];
long long mid=0;
while(l<=r)
{
mid=(l+r)/2; //寫到這明白了為什麼許多人寫成 l+(r-l)/2 這樣不容易溢位,如果直接(l+r)/2,當l=r=2000000000時
//雖然這個時候l和r都沒有超出int的界限,但是l+r 卻溢位,導致RE,這時可以l,r,mid全改為long long 。
int cnt1=0;
int cnt2=0;
for (int i=0;i<n;i++)
{
auto m=mm[i];
cnt1=cnt1+lower_bound(m.begin(),m.end(),mid)-m.begin(); //upper_bound() 這兩個迭代器相減的結果的數值是比 //mid小的元素的個數。
cnt2=cnt2+upper_bound(m.begin(),m.end(),mid)-m.begin(); // upper_bound() 這兩個迭代器相減的結果的數值是不 //小於mid的元素個數。
}
if (k>cnt1&&k<=cnt2)
return mid;
if (k>cnt2)
l=mid+1;
else
r=mid-1;
}
return mid;
}
};
看了好幾遍終於懂了一點,抓緊把理解的寫下來。最近感覺好累,最近的事情太多了。