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。
解題思路:優先隊列
使用最大堆,當隊列中的元素大於k時,便彈出隊頭元素,由於使用的是最大堆模式,所以最後返回隊頭元素(即爲有序矩陣中第k小的元素)
- C++實現
class Solution {
public:
int kthSmallest(vector<vector<int>>& matrix, int k) {
priority_queue<int> pq;
int rows = matrix.size();
int cols = matrix[0].size();
for(int row = 0;row < rows;row++){
for(int col = 0; col <cols;col++){
pq.push(matrix[row][col]);
if(pq.size() > k){
pq.pop();
}
}
}
return pq.top();
}
};
- Python
class Solution:
def kthSmallest(self, matrix: List[List[int]], k: int) -> int:
res = []
rows = len(matrix)
cols = len(matrix[0])
for i in range(rows):
for j in range(cols):
res.append(matrix[i][j])
#sorted是爲了解決[[1,2],[1,3]] k=2這個測試案例
return sorted(res)[k-1]
215. 數組中的第K個最大元素
在未排序的數組中找到第 k 個最大的元素。請注意,你需要找的是數組排序後的第 k 個最大的元素,而不是第 k 個不同的元素。
示例 1:
輸入: [3,2,1,5,6,4] 和 k = 2
輸出: 5
示例 2:
輸入: [3,2,3,1,2,4,5,5,6] 和 k = 4
輸出: 4
說明:
你可以假設 k 總是有效的,且 1 ≤ k ≤ 數組的長度。
解題方法:暴力法,直接升序排序之後取倒數第k個值
- C++
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
int size = nums.size();
sort(begin(nums), end(nums));
return nums[size - k];
//算法的時間複雜度爲 O(NlogN),空間複雜度爲 O(1)
}
};
- Python
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
#從小到大排序,第k個最大元素即倒數第k個元素
return sorted(nums)[-k]
#算法的時間複雜度爲 O(NlogN),空間複雜度爲 O(1)
解題思路2:快速排序,藉助 partition 操作定位到最終排定以後索引爲 len - k 的那個元素(特別注意:隨機化切分元素
partition(切分)操作,使得:
- 對於某個索引 j,nums[j] 已經排定,即 nums[j] 經過 partition(切分)操作以後會放置在它 “最終應該放置的地方”;
- nums[left] 到 nums[j - 1] 中的所有元素都不大於 nums[j];
- nums[j + 1] 到 nums[right] 中的所有元素都不小於 nums[j]。
partition(切分)操作總能排定一個元素,還能夠知道這個元素它最終所在的位置,這樣每經過一次 partition(切分)操作就能縮小搜索的範圍,這樣的思想叫做 “減而治之”(是 “分而治之” 思想的特例)。
切分過程可以不借助額外的數組空間,僅通過交換數組元素實現。
- Python
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
size = len(nums)
target = size - k
left = 0
right = size - 1
while True:
index = self.partition(nums, left, right)
if index == target:
return nums[index]
elif index < target:
# 下一輪在 [index + 1, right] 裏找
left = index + 1
else:
right = index - 1
# 循環不變量:[left + 1, j] < pivot
# (j, i) >= pivot
def partition(self, nums, left, right):
pivot = nums[left]
j = left
for i in range(left + 1, right + 1):
if nums[i] < pivot:
j += 1
nums[i], nums[j] = nums[j], nums[i]
nums[left], nums[j] = nums[j], nums[left]
return j
最小的K個數
設計一個算法,找出數組中最小的k個數。以任意順序返回這k個數均可。
示例:
輸入: arr = [1,3,5,7,2,4,6,8], k = 4
輸出: [1,2,3,4]
提示:
0 <= len(arr) <= 100000
0 <= k <= min(100000, len(arr))
解題思路:利用優先隊列的思想,做法與LeetCode 378. 有序矩陣中第K小的元素類似
- C++
class Solution {
public:
vector<int> smallestK(vector<int>& arr, int k) {
//priority_queue容器,默認從小到大排序,底層實現爲最大堆
priority_queue<int> pq;
vector<int> res;
for(auto x : arr){
pq.push(x);
if(pq.size() > k){
pq.pop();
}
}
while(!pq.empty()){
res.push_back(pq.top());
pq.pop();
}
return res;
}
};
- Python :利用sorted函數,一行代碼解決
class Solution:
def smallestK(self, arr: List[int], k: int) -> List[int]:
return sorted(arr)[:k]