378. 有序矩陣中第K小的元素(C++)---基於堆排序的方法 / 二分法 解題

題目詳情

給定一個 n x n 矩陣,其中每行和每列元素均按升序排序,找到矩陣中第 k 小的元素。
請注意,它是排序後的第 k 小元素,而不是第 k 個不同的元素。

 

示例:

matrix = [
   [ 1,  5,  9],
   [10, 11, 13],
   [12, 13, 15]
],
k = 8,

返回 13。

提示:
你可以假設 k 的值永遠是有效的,1 ≤ k ≤ n2 。


——題目難度:中等

 




基於堆排序的方法

關於優先隊列的使用 可以看看這篇——215. 數組中的第K個最大元素(C++)---基於快排的方法 / 基於堆排序的方法(包含優先隊列的使用總結)
思路大概是:可以限制一個元素大小爲k的大頂堆,當遍歷完一遍matrix後,隊首元素就是第 k 小的元素了(依賴於優先隊列內部的自動排序)。

-使用優先隊列解題代碼如下(精簡版)

class Solution {
public:
    int kthSmallest(vector<vector<int>>& matrix, int k) {
		priority_queue<int, vector<int>, less<int>> pq;
		for(int i = 0; i < matrix.size(); i++)
		{
			for(int j = 0; j < matrix[0].size(); j++)
			{
				pq.push(matrix[i][j]);
				if (pq.size() > k) pq.pop();
			}
		}
		
		return pq.top();
    }
};




上面的代碼運行起來有點慢,是因爲pq.push(matrix[i][j]);
因爲不加判斷 直接加入隊列,這樣優先隊列內部進行的自動排序 次數就會變多,所以運行起來也就越慢。

-下面的改進的代碼(增加判斷語句 以 減少隊列內部進行的自動排序的次數)

class Solution {
public:
    int kthSmallest(vector<vector<int>>& matrix, int k) {
		priority_queue<int, vector<int>, less<int>> pq;
		for(int i = 0; i < matrix.size(); i++)
		{
			for(int j = 0; j < matrix[0].size(); j++)
			{
				int temp = matrix[i][j];
				if (pq.size() == k && temp < pq.top()) {
					pq.pop();
					pq.push(temp);
				} 
				else if (pq.size() == k) {
					continue;
				}
				else {
					pq.push(temp);
				}
			}
		}
		
		return pq.top();
    }
};

←這樣比之前快了一點點。


 



二分法

解法參考力扣—官方題解裏的二分解法,在進行模擬二分法的時候 可以把 二維數組matrix裏的 全部元素 看成 排好序的 一維數組,這樣可以比較好理解此題的二分解法。

且不用擔心 這裏的二分法 找不到那個待求數,因爲每次循環中都保證了第k小的數在left~right之間,當left==right時,第k小的數即被找出,等於left(right也是一樣的)。

-解題代碼

class Solution {
public:
    int kthSmallest(vector<vector<int>>& matrix, int k) {
		int l = matrix[0][0];
		int r = matrix.back().back();
		while (l < r) {
			int mid = (l + r) / 2;
			int count = search_less_count(matrix, mid);
			if (count < k) {
				l = mid + 1;
			} else {
				r = mid;
			}
		}
		
		return l;
    }
    
    int search_less_count(vector<vector<int>>& matrix, int target) {
    	int cnt = 0;
    	//從左下角開始查找 
    	int n = matrix.size();
    	int i = n - 1, j = 0;
    	while (i >= 0 && j < n) {
    		if (target >= matrix[i][j]) {
    			cnt += i + 1;
    			j++;
    		} else {
    			i--;
    		}
    	}
    	
    	return cnt;
    }
};

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