378 有序矩陣中第K小的元素

2021-10-07 18:37:50 字數 3275 閱讀 8044

題目:給定乙個 n x n 矩陣,其中每行和每列元素均按公升序排序,找到矩陣中第 k 小的元素

思路及演算法

由題目給出的性質可知,這個矩陣的每一行均為乙個有序陣列。問題即轉化為從這 n 個有序陣列中找第 k 大的數,可以想到利用歸併排序的做法,歸併到第 k 個數即可停止。

一般歸併排序是兩個陣列歸併,而本題是 n 個陣列歸併,所以需要用小根堆維護,以優化時間複雜度。

public

intkthsmallest2

(int

matrix,

int k)})

;int n = matrix.length;

for(

int i =

0; i < n; i++))

;}//維護最左側的一列最小值候選人,當有序佇列彈出7個最小值,此時佇列中的最小值即為所求

for(

int i =

0; i < k -

1; i++))

;}}return pq.

poll()

[0];

}

時間複雜度:o(klogn),歸併 k 次,每次堆中插入和彈出的操作時間複雜度均為logn。

空間複雜度:o(n),堆的大小始終為 n。

其實解決這個問題的關鍵,在於維護一組「最小值候選人」

在整個矩陣中,每次彈出矩陣中最小的值,第k個被彈出的就是我們需要的數字。

現在我們的目的很明確:每次彈出矩陣中最小的值。你需要保證最小值必然從這組候選人中產生,於是每次只要從候選人中彈出最小的乙個即可。

我們來選擇第一組候選人,在這裡可以選擇第一列,因為每乙個數字都是其對應行的最小值,全域性最小值也必然在其中。然後使用prorityqueue有序佇列來儲存這一組候選人,就能保證每次從佇列中彈出的都是候選人中的最小值。

例:選取以下矩陣,開始的候選人為第一列,然後每次選擇候選人中的最小值彈出,然後被彈出的那一行的候選人右移以為記得到該行新的候選人,當某一行的值彈完後將候選人佇列中長度減1即可,知道彈出第k-1個值,此時最小值佇列的值即為所求第k小的值

步驟如下圖所示:

思路及演算法

由題目給出的性質可知,這個矩陣內的元素是從左上到右下遞增的(假設矩陣左上角為 matrix[0][0])。以下圖為例:

我們知道整個二維陣列中 matrix[0][0] 為最小值,matrix[n−1][n−1] 為最大值,現在我們將其分別記作 l 和 r。

可以發現乙個性質:任取乙個數 mid 滿足l≤mid≤r,那麼矩陣中不大於 mid 的數,肯定全部分布在矩陣的左上角。

例如下圖,取 mid=8:

我們可以看到,矩陣中大於 mid 的數就和不大於 mid 的數分別形成了兩個板塊,沿著一條鋸齒線將這個矩形分開。其中左上角板塊的大小即為矩陣中不大於 mid 的數的數量。

我們只要沿著這條鋸齒線走一遍即可計算出這兩個板塊的大小,也自然就統計出了這個矩陣中不大於mid 的數的個數了。

走法演示如下,依然取 mid=8:

可以這樣描述走法:

1、初始位置在 matrix[n−1][0](即左下角);

2、設當前位置為 matrix[i][j]。若 matrix[i][j]≤mid,則將當前所在列的不大於 mid 的數的數量(即 i+1)累加到答案中,並向右移動,否則向上移動;

3、不斷移動直到走出格仔為止。

我們發現這樣的走法時間複雜度為 o(n),即我們可以線性計算對於任意乙個 mid,矩陣中有多少數不大於它。這滿足了二分查詢的性質。

不妨假設答案為 x,那麼可以知道 l≤x≤r,這樣就確定了二分查詢的上下界。

每次對於「猜測」的答案 mid,計算矩陣中有多少數不大於mid

如果數量不少於 k,那麼說明最終答案 x 不大於 mid;

如果數量少於 k,那麼說明最終答案 x 大於 mid。

這樣我們就可以計算出最終的結果 x 了。

public

intkthsmallest3

(int

matrix,

int k)

else

}return left;

}//判斷數量是否大於k

public

boolean

check

(int

matrix,

int mid,

int k,

int n)

else

}return num >= k;

}

時間複雜度:o(nlog(r−l)),二分查詢進行次數為 o(log(r−l)),每次操作時間複雜度為 o(n)。

空間複雜度:o(1)。

public

intkthsmallest

(int

matrix,

int k)

} arrays.

sort

(sorted)

;return sorted[k-1]

;}

時間複雜度:o(n^2logn),對 n^2個數排序。

空間複雜度:o(n^2),一維陣列需要儲存這 n^2個數。

暴力法容易理解,就是直接先把二維陣列轉換為一維陣列,然後對該一維陣列排序(呼叫arrays.sort()函式即可),然後排序後陣列中下標為k-1的值即為所求,但是這種方法沒有用到有序陣列的性質,而且新產生了乙個n*n的一維陣列,所以時間和空間複雜度都很高。

其它方法自行檢視leetcode官方題解。

參考:leetcode題解1

leecode官方題解

378 有序矩陣中第K小的元素

378.有序矩陣中第k小的元素 給定乙個n x n矩陣,其中每行和每列元素均按公升序排序,找到矩陣中第k小的元素。請注意,它是排序後的第k小元素,而不是第k個不同的元素。示例 matrix 1,5,9 10,11,13 12,13,15 k 8,返回 13。你可以假設 k 的值永遠是有效的,1 k ...

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 ...

378 有序矩陣中第K小的元素

給定乙個n x n矩陣,其中每行和每列元素均按公升序排序,找到矩陣中第k小的元素。請注意,它是排序後的第k小元素,而不是第k個不同的元素。示例 matrix 1,5,9 10,11,13 12,13,15 k 8,返回 13。思路 在matrix 0 0 matrix length 1 length...