• leetcode topk海量数据


    题目

    在学习数据结构的过程,一定会遇到这样一道题目,海量数据中查找前k个最大/最小的数,LeetCode题目面试题40. 最小的k个数:输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

    解题思路

    入门级

    1. 整体排序:直接使用C++ sort函数,sort是基于快排的优化
    class Solution {
    public:
        vector<int> getLeastNumbers(vector<int>& arr, int k) {
            vector<int> ans;
            sort(arr.begin(), arr.end());
            for (int i = 0; i < k; ++i)
                ans.push_back(arr[i]);
            return ans;
        }
    };
    
    1. 部分排序:直接进行k次遍历,找到前k个最小的数字,类似于简单选择排序(打扑克牌)
    class Solution {
    public:
        vector<int> getLeastNumbers(vector<int>& arr, int k) {
            int len = arr.size();
            int min, min_index;
            vector<int> ans;
            for (int i = 0; i < k; ++i)
            {
                min = arr[i];
                min_index = i;
                for (int j = i+1; j < len; ++j)
                {
                    if (min > arr[j])
                    {
                        min = arr[j];
                        min_index = j;   
                    }
                }
                ans.push_back(arr[min_index]);
                arr[min_index] = arr[i];
            }
            return ans;
        }
    };
    

    进阶

    1. 快排:借助快排的特点,每一趟快排都会找到一个确切的位置,小的数在左边,大的数在右边,所以只要快排找到第k个位置的数字即可,不用对整个数组进行多余的排序操作。
    class Solution {
    public:
        vector<int> getLeastNumbers(vector<int>& arr, int k) {
            vector<int> ans;
            if (k==0)
                return ans;
            quick_sort(arr, 0, arr.size()-1, k);
            for (int i = 0; i < k; ++i)
                ans.push_back(arr[i]);
            return ans;
        }
        void quick_sort(vector<int> &arr, int low, int high, int k)
        {
            if (low < high)
            {
                int pivot_positon = partition(arr, low, high);
                if (pivot_positon > k-1 )
                    quick_sort(arr, low, pivot_positon-1, k);
                else if (pivot_positon < k -1)
                    quick_sort(arr, pivot_positon+1, high, k);
            }
        }
        int partition(vector<int> &arr, int low, int high)
        {
            int pivot = arr[low];
            while (low < high)
            {
                while (low<high && arr[high]>=pivot)//此处不要少了=,否则相同的数据会死循环
                    --high;
                arr[low] = arr[high];
                while (low<high && arr[low]<pivot)
                    ++low;
                arr[high] = arr[low];
            }
            arr[low] = pivot;
            return low;
        }
    };
    
    1. 最小(大)堆:用堆作为数据结构来管理数据,堆是一棵完全二叉树,完全二叉树因为结构的特殊性,父节点的下标是子节点下标一半,所以通常用数组很好表示。堆排序分为构造堆和排序两个过程

    class Solution {
    public:
        vector<int> getLeastNumbers(vector<int>& arr, int k) {
            if(k == 0) return vector<int>();
            vector<int> max_heap_vec(arr.begin(), arr.begin()+k);
            //对前k个数构造最大堆
            buildMaxHeap(max_heap_vec);
            //剩余的数插入堆里,堆顶部是最大值,出现比最大值还小的数时,替换掉堆顶,然后把堆顶元素向下调整,形成新的最大堆。
            for(int i = k; i<arr.size(); ++i){
                // 出现比堆顶元素小的值, 置换堆顶元素, 并调整堆
                if(arr[i] < max_heap_vec[0])
                {
                    max_heap_vec[0] = arr[i];
                    downAdjust(max_heap_vec, 0);
                }
            }
            return max_heap_vec;
        }
    private:
        void buildMaxHeap(vector<int>& v){
            // 所有非叶子节点从后往前依次下沉
            for(int i = static_cast<int>(v.size()-1) / 2; i>=0; --i) //最后一个叶结点的父节点开始,父节点向下调整,直到根节点调整完成
            {
                downAdjust(v, i);
            }
        }
    
        void downAdjust(vector<int>& v, int index)
        {
            int parent = v[index];
            // 左孩子节点索引,若有子节点,左孩子必然存在,完全二叉树特点
            int child_index = 2*index;
            while(child_index < v.size()){
                // 判断是否存在右孩子, 并选出较大的节点
                if(child_index+1 < v.size() && v[child_index+1] > v[child_index]){
                    ++child_index;
                }
                // 判断父节点和子节点的大小关系
                if(parent >= v[child_index])
                    break;
                // 较大节点上浮
                v[index] = v[child_index];
                index = child_index;
                child_index = 2*index;
            }
            v[index] = parent;
        }
    };
    
    
  • 相关阅读:
    制定并分享愿景 领导的艺术之一
    不要非黑即白,有些数据即使只有90%的准确,也是有用的
    双赢的思维考虑问题
    利用一切机会丰富自己的知识,利用一切机会调整自己的行为,为了达成目标而与他人合作,取得共赢 update by June 2012
    数据说话 说服别人
    对重要的事情,要很快做出反应
    You can if you think you can
    宽容的心态,开明的头脑
    DataGridView上下移动行及设置当前行
    sql 数据库、表
  • 原文地址:https://www.cnblogs.com/vito_wang/p/12531965.html
Copyright © 2020-2023  润新知