1. 程式人生 > 其它 >Top-K問題

Top-K問題

快速排序

快速排序法

快速排序演算法兩個核心點,分別為 “哨兵劃分” 和 “遞迴” 。有點像二分法

  • 哨兵劃分操作:以陣列某個元素(常常選取首元素)為基準數key,called哨兵 ,將所有小於哨兵的元素移動至哨兵的左邊,大於哨兵的元素移動至哨兵的右邊。


  • 遞迴操作:對左子陣列右子陣列遞迴執行 “哨兵劃分操作”,直至子陣列長度為 1 時終止遞迴,即可完成對整個陣列的排序。
複雜度分析:

時間複雜度 O(N log N): 庫函式sorted(arr) arr.sort()、快排等排序演算法的平均時間複雜度為O(NlogN) 。
空間複雜度 O(N)O(N) : 快速排序的遞迴深度最好(平均)為 O(logN) ,最差情況(即輸入陣列完全倒序)為O(N)。

    void quickSort(vector<int>& arr,int l, int r){
        //當子數字長度為1時終止
        if(l>=r) return;
        //選取第一個元素arr[1]作為哨兵   做“哨兵劃分操作”
        int i=l,j=r;
        while(i<j){
            while(arr[j]>=arr[l] && i<j) j--;
            while(arr[i]<=arr[l] && i<j) i++;
            swap(arr[i],arr[j]);
        }
        swap(arr[i],arr[l]);
        
// 遞迴操作 分別對 左子陣列 和 右子陣列 quickSort(arr,l,i-1); quickSort(arr,i+1,r); }
def quickSort(arr,l,r):
    if l>=r: return
    i,j = l,r
    while i<j:
        while i<j and arr[j] >= arr[l]: j-=1
        while i<j and arr[i] <= arr[l]: i+=1
        arr[i],arr[j] = arr[j],arr[i]
    arr[i],arr[l] 
= arr[l],arr[i] quickSort(arr,l,i-1) quickSort(arr,i+1,r) quickSort(arr,0,len(arr)-1)
pytho快排

圖片來自:https://www.cnblogs.com/l199616j/p/10597245.html(快排)

P.S. 根據不同的順序要求,可以將順序程式碼更改(但核心其實還是一樣的:哨兵+遞迴),應用在不同的場景中,舉個栗子:

class SolutionOfminNumber {
public:
    //https://leetcode-cn.com/problems/ba-shu-zu-pai-cheng-zui-xiao-de-shu-lcof/
    // 這題本質上是排序題  要求的順序是整個拼接起來的字串最小 核心就是 任意兩個數a, b  若a + b > b + a  則 b->a  否則 a->b
    // 套用任何排序方法就可以   最後再做一次字串拼接
    string minNumber(vector<int>& nums) {
        vector<string> strs;
        string res = "";
        for (int i = 0; i < nums.size(); i++) {
            strs.push_back(to_string(nums[i]));
        }
        quick_sort(0, strs.size() - 1, strs);
        for (int i = 0; i < strs.size(); i++) {
            res += strs[i];
        }
        return res;

    }

    void quick_sort(int left, int right, vector<string>& strs) {
        if (left >= right) return;
        int i = left;
        int j = right;
        while (i < j) {
            while (strs[j] + strs[left] >= strs[left] + strs[j] && i < j) j -= 1;
            while (strs[i] + strs[left] <= strs[left] + strs[i] && i < j) i += 1;
            string temp = strs[i];
            strs[i] = strs[j];
            strs[j] = temp;
        }
        string temp = strs[i];
        strs[i] = strs[left];
        strs[left] = temp;
        quick_sort(left, i - 1, strs);
        quick_sort(i + 1, right, strs);
    }

    /* solution in python
    def minNumber(self, nums: List[int]) -> str:
        def quick_sort(left,right):
            if left >= right:return #停止的標誌
            i,j = left,right
            while i<j: #這步要重複 直到i==j
                while strs[j]+strs[left]>=strs[left]+strs[j] and i<j:j-=1
                while strs[i]+strs[left]<=strs[left]+strs[i] and i<j:i+=1
                strs[i],strs[j]=strs[j],strs[i]
            strs[i],strs[left]=strs[left],strs[i]
            quick_sort(left,i-1)
            quick_sort(i+1,right)
        strs = [str(num) for num in nums]
        quick_sort(0,len(strs) -1)
        return ''.join(strs)

    */


    /* 快速排序C語言
    void sort(int *a, int left, int right)
    {
        if(left >= right)//如果左邊索引大於或者等於右邊的索引就代表已經整理完成一個組了{
            return ;
        }

        int i = left;
        int j = right;
        int key = a[left];

        while(i < j)                               //控制在當組內尋找一遍
        {
            while(i < j && key <= a[j])
            //而尋找結束的條件就是,1,找到一個小於或者大於key的數(大於或小於取決於你想升
            //序還是降序)2,沒有符合條件1的,並且i與j的大小沒有反轉
            {
                j--;//向前尋找
            }

            swap(a,i,j);//交換a[i]和a[j]的數值
            //找到一個這樣的數後就把它賦給前面的被拿走的i的值(如果第一次迴圈且key是a[left],那麼就是給key)

            while(i < j && key >= a[i])//這是i在當組內向前尋找,同上,不過注意與key的大小關係停止迴圈和上面相反,因為排序思想是把數往兩邊扔,所以左右兩邊的數大小與key的關係相反
            {
                i++;
            }

            swap(a,i,j);
        }

        sort(a, left, i - 1);//最後用同樣的方式對分出來的左邊的小組進行同上的做法
        sort(a, i + 1, right);//用同樣的方式對分出來的右邊的小組進行同上的做法
        //當然最後可能會出現很多分左右,直到每一組的i = j 為止
    }
    */




};

Top-K問題快排解法

class Solution {
public:
    //https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/
    //返回陣列的前k大
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        quickSort(arr,0,arr.size()-1);
        vector<int> res;
        //返回排序後的arr的前k個元素的vector  擷取vector 
        res.assign(arr.begin(),arr.begin()+k);
        return res;
    }

    void quickSort(vector<int>& arr,int l, int r){
        //當子數字長度為1時終止
        if(l>=r) return;
        //選取第一個元素arr[1]作為哨兵   做“哨兵劃分操作”
        int i=l,j=r;
        while(i<j){
            while(arr[j]>=arr[l] && i<j) j--;
            while(arr[i]<=arr[l] && i<j) i++;
            swap(arr[i],arr[j]);
        }
        swap(arr[i],arr[l]);
        // 遞迴操作  分別對 左子陣列 和 右子陣列
        quickSort(arr,l,i-1);
        quickSort(arr,i+1,r);
    }
};