劍指Offer&LeetCode:一文詳述面試中的TOP K系列問題解決方案

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