easy 剑指 Offer 最小的k个数 排序 优先队列 递归快排

在这里插入图片描述


排序函数:

c++

vector 排序


class Solution {
public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        vector<int> res(k, 0);         // vector 初始化
        sort(arr.begin(), arr.end());  // 小到大排序
        int c=0;
        for (auto i:arr){
            if(c<k){
                res.push_back(i);
                c++;
            }
        }
        return res;
    }
};

python

list 排序


class Solution:
    def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
        arr = sorted(arr)  # 大到小排序sorted(a,reverse=True)
        res = []
        c=0
        for i in arr:
            if c<k:
                res.append(i)
                c += 1
        
        return res

在这里插入图片描述


维护一个k个最小数的堆:

最小最大堆用优先队列实现

优先队列 c++

1. 普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。
2. 在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出。
3. 优先队列具有队列的所有特性,包括基本操作,只是在这基础上添加了内部的一个排序

在这里插入图片描述

// c++默认是大顶堆 大的值有最高优先级
priority_queue <int,vector<int>,less<int> >q;  //降序队列,大顶堆
priority_queue <int> q;  // //降序队列,大顶堆
priority_queue <int,vector<int>,greater<int> > q;  //升序队列,小顶堆

class Solution {
public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        vector<int> res(k, 0); 
        if (k == 0) { // 排除 0 的情况
            return res;
        }
        //queue <int> que;   // 普通队列
        priority_queue <int> que;  // 优先队列,另外定义优先级,优先级高的先出
        int n = arr.size();
        for(int i = 0; i < k; i++) {
            que.push(arr[i]);
        }
        for(int i=k; i<n; i++){ // 优先队列每次进新数都会内部排序,对顶是最大的数,有最高优先级
            if (que.top() > arr[i]) {
                que.pop();     // 大的数弹出
                que.push(arr[i]);
            }
        }
        for (int i = 0; i < k; i++) {  //队列中数弹出给vector返回
            res[i] = que.top();
            que.pop();
        }

        return res;
    }
};

python

c++ 默认最大堆,即优先队列中对顶是最大数,大到小排序
python 默认最小堆,即优先队列中对顶是最小数,小到大排序


class Solution:
    def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
        if k == 0:
            return []
        hp = [-x for x in arr[:k]] #列表前k个数取相反数,则python优先队列,队顶最小数其实是取相反数前的最大数
        heapq.heapify(hp)  # 将列表hp原地转换成堆 import heapq heap[0]总是最小的那个元素
        for i in range(k, len(arr)):  # 从第k个数开始与队顶比较
            if -hp[0]>arr[i]:   # 取反才是原来的数
                heapq.heappop(hp)  # hp 弹出队顶
                heapq.heappush(hp, -arr[i])   # arr[i]取反加入堆 (进入后堆将内部排序)
        res = [-x for x in hp]
        return res

在这里插入图片描述


快排

快排算法

c++


class Solution {

private:
    void quickSort(vector<int>& arr, int l, int r){
        // 子数组长度为 1 时终止递归
        if (l >= r){
            return;
        }
        // 哨兵划分操作(以 arr[l] 作为基准数)
        int i = l, j = r;  // i j 左右哨兵位置
        while (i < j){
            while (i < j && arr[j] >= arr[l]) j--;  // 右指针找到比基准数更小的(必须右边的哨兵先动)
            while (i < j && arr[i] <= arr[l]) i++;  // 作指针找到比基准数更大的
            swap(arr[i], arr[j]);                   // 交换
        }
        swap(arr[i], arr[l]);
        // 快排完成
        // 递归左(右)子数组执行哨兵划分
        quickSort(arr, l, i - 1);  // 左子数组
        quickSort(arr, i + 1, r);  // 右子数组
    }

public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        quickSort(arr, 0, arr.size() - 1);  // 快排递归函数(数组,起始,终止)
        vector<int> res;
        res.assign(arr.begin(), arr.begin() + k);  // 区间[first,last)的元素赋值到当前的vector容器
        
        return res;
    }
};

python


class Solution:
    def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
        def quick_sort(arr, l, r):
            # 子数组长度为 1 时终止递归
            if l >= r: 
                return
            # 哨兵划分操作(以 arr[l] 作为基准数)
            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]     # swap(arr[i], arr[l]); c++

            arr[i], arr[l] = arr[l], arr[i]         # swap(arr[i], arr[l])

            # 左右子数组递归开始,此时位置i是分界点
            quick_sort(arr,l,i-1)
            quick_sort(arr,i+1,r)

        quick_sort(arr, 0, len(arr) - 1)  # 调用递归函数  全排列arr
        return arr[:k]     # arr是已经从小到大排序的,返回前k个   


在这里插入图片描述


基于快速排序的数组划分

在这里插入图片描述

c++


class Solution {

private:
    vector<int> quickSort(vector<int>& arr, int k, int l, int r){ // 函数返回前k个排序
        int i = l, j = r;
        while (i < j) {
            while (i < j && arr[j] >= arr[l]) j--;
            while (i < j && arr[i] <= arr[l]) i++;
            swap(arr[i], arr[j]);
        }
        swap(arr[i], arr[l]);

        if (i > k) return quickSort(arr, k, l, i - 1);  // k在分界点i左边,只快排左子数组(下一个分界点左移动一个,以递归找到位置k)
        if (i < k) return quickSort(arr, k, i + 1, r);  // k在分界点i右边,只快排右子数组(下一个分界右移动一个,以递归找到位置k)
        vector<int> res;
        res.assign(arr.begin(), arr.begin() + k);  // 前k个赋值给res

        return res;
    }
    

public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        if (k >= arr.size()){
            return arr;  // 若 k 大于数组长度,则直接返回整个数组;
        }

        return quickSort(arr, k, 0, arr.size() - 1);  // 快排
    }
};

python


class Solution:
    def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
        if k >= len(arr): return arr                #  若 k 大于数组长度,则直接返回整个数组;
        def quick_sort(l, r):
            # 哨兵划分操作(以 arr[l] 作为基准数)
            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]     # swap(arr[i], arr[l]); c++

            arr[i], arr[l] = arr[l], arr[i]         # swap(arr[i], arr[l])

            if i<k: return quick_sort(i+1,r)    # k比分界点i右,下一次排序右边界右移
            if i>k: return quick_sort(l,i-1)    # k比分界点i左,下一次排序右边界左移

            return arr[:k]  # 递归终止条件:i==k

        return quick_sort(0, len(arr) - 1)  

在这里插入图片描述


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值