Sort - leetcode 【排序】

215. Kth Largest Element in an Array

4 C++ Solutions using Partition, Max-Heap, priority_queue and multiset respectively

Well, this problem has a naive solution, which is to sort the array in descending order and return the k-1-th element.

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        sort(nums.begin(), nums.end());
        return nums[k - 1];
    }
};

However, sorting algorithm gives O(nlogn) complexity. Suppose n = 10000 and k = 2, then we are doing a lot of unnecessary operations. In fact, this problem has at least two simple and faster solutions.

Well, the faster solution has no mystery. It is also closely related to sorting. I will give two algorithms for this problem below, one using quicksort(specifically, the partition subroutine) and the other using heapsort.



Quicksort

In quicksort, in each iteration, we need to select a pivot and then partition the array into three parts:

  1. Elements smaller than the pivot;
  2. Elements equal to the pivot;
  3. Elements larger than the pivot.

Now, let‘s do an example with the array [3, 2, 1, 5, 4, 6] in the problem statement. Let‘s assume in each time we select the leftmost element to be the pivot, in this case, 3. We then use it to partition the array into the above 3 parts, which results in [1, 2, 3, 5, 4, 6]. Now 3 is in the third position and we know that it is the third smallest element. Now, do you recognize that this subroutine can be used to solve this problem?

In fact, the above partition puts elements smaller than the pivot before the pivot and thus the pivot will then be the k-th smallest element if it is at the k-1-th position. Since the problem requires us to find the k-th largest element, we can simply modify the partition to put elements larger than the pivot before the pivot. That is, after partition, the array becomes [5, 6, 4, 3, 1, 2]. Now we know that 3 is the 4-th largest element. If we are asked to find the 2-th largest element, then we know it is left to 3. If we are asked to find the 5-th largest element, then we know it is right to 3. So, in the average sense, the problem is reduced to approximately half of its original size, giving the recursion T(n) = T(n/2) + O(n) in which O(n) is the time for partition. This recursion, once solved, gives T(n) = O(n) and thus we have a linear time solution. Note that since we only need to consider one half of the array, the time complexity is O(n). If we need to consider both the two halves of the array, like quicksort, then the recursion will be T(n) = 2T(n/2) + O(n) and the complexity will be O(nlogn).

Of course, O(n) is the average time complexity. In the worst case, the recursion may become T(n) = T(n - 1) + O(n) and the complexity will be O(n^2).

Now let‘s briefly write down the algorithm before writing our codes.

  1. Initialize left to be 0 and right to be nums.size() - 1;
  2. Partition the array, if the pivot is at the k-1-th position, return it (we are done);
  3. If the pivot is right to the k-1-th position, update right to be the left neighbor of the pivot;
  4. Else update left to be the right neighbor of the pivot.
  5. Repeat 2.

Now let‘s turn it into code.

class Solution {
public:
    int partition(vector<int>& nums, int left, int right) {
        int pivot = nums[left];
        int l = left + 1, r = right;
        while (l <= r) {
            if (nums[l] < pivot && nums[r] > pivot)
                swap(nums[l++], nums[r--]);
            if (nums[l] >= pivot) l++;
            if (nums[r] <= pivot) r--;
        }
        swap(nums[left], nums[r]);
        return r;
    }

    int findKthLargest(vector<int>& nums, int k) {
        int left = 0, right = nums.size() - 1;
        while (true) {
            int pos = partition(nums, left, right);
            if (pos == k - 1) return nums[pos];
            if (pos > k - 1) right = pos - 1;
            else left = pos + 1;
        }
    }
};


Heapsort

Well, this problem still has a tag "heap". If you are familiar with heapsort, you can solve this problem using the following idea:

  1. Build a max-heap for nums, set heap_size to be nums.size();
  2. Swap nums[0] (after buding the max-heap, it will be the largest element) with nums[heap_size - 1] (currently the last element). Then decrease heap_size by 1 and max-heapify nums (recovering its max-heap property) at index 0;
  3. Repeat 2 for k times and the k-th largest element will be stored finally at nums[heap_size].

Now I paste my code below. If you find it tricky, I suggest you to read the Heapsort chapter of Introduction to Algorithms, which has a nice explanation of the algorithm. My code simply translates the pseudo code in that book :-)

class Solution {
public:
    inline int left(int idx) {
        return (idx << 1) + 1;
    }
    inline int right(int idx) {
        return (idx << 1) + 2;
    }
    void max_heapify(vector<int>& nums, int idx) {
        int largest = idx;
        int l = left(idx), r = right(idx);
        if (l < heap_size && nums[l] > nums[largest]) largest = l;
        if (r < heap_size && nums[r] > nums[largest]) largest = r;
        if (largest != idx) {
            swap(nums[idx], nums[largest]);
            max_heapify(nums, largest);
        }
    }
    void build_max_heap(vector<int>& nums) {
        heap_size = nums.size();
        for (int i = (heap_size >> 1) - 1; i >= 0; i--)
            max_heapify(nums, i);
    }
    int findKthLargest(vector<int>& nums, int k) {
        build_max_heap(nums);
        for (int i = 0; i < k; i++) {
            swap(nums[0], nums[heap_size - 1]);
            heap_size--;
            max_heapify(nums, 0);
        }
        return nums[heap_size];
    }
private:
    int heap_size;
}

If we are allowed to use the built-in priority_queue, the code will be much more shorter :-)

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        priority_queue<int> pq(nums.begin(), nums.end());
        for (int i = 0; i < k - 1; i++)
            pq.pop();
        return pq.top();
    }
};

Well, the priority_queue can also be replaced by multiset :-)

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        multiset<int> mset;
        int n = nums.size();
        for (int i = 0; i < n; i++) {
            mset.insert(nums[i]);
            if (mset.size() > k)
                mset.erase(mset.begin());
        }
        return *mset.begin();
    }
};
时间: 2024-10-06 00:01:55

Sort - leetcode 【排序】的相关文章

使用 redis (sort set排序集合类型操作)

sort set排序集合类型 释义: sort set 是 string 类型的集合 sort set 的每个元素 都会关联一个 权 通过 权值 可以有序的获取集合中的元素 应用场合: 获取热门帖子(回复量)信息: select * from message order by backnum desc limit 5; // 利用 sort set 实现最热门的前 5 贴信息 帖子id            回复量(万条) 11                102        12     

Linux Shell sort 指定排序第几列

ip.txt 里存储着ip信息 统计排序后取前10条 awk '{cnt[$1]++} END{for (ip in cnt) print ip":"cnt[ip]}' ip.txt | sort -k 2 -rn -t":" | head -n 10 awk '{cnt[$1]++} END{for (ip in cnt) print cnt[ip],ip}' ip.txt | sort -rn | head -n 10 sort -k  根据第几列排序  -n

counting sort 计数排序

//counting sort 计数排序 //参考算法导论8.2节 #include<cstdio> #include<cstring> #include<algorithm> #include<cassert> using namespace std; const int k=5; const int n=7; int a[n]={5, 5, 1, 2 , 5, 4, 1}; int b[n]; int c[k+1]; int main() { int m

Uva-------(11462) Age Sort(计数排序)

B Age Sort Input: Standard Input Output: Standard Output   You are given the ages (in years) of all people of a country with at least 1 year of age. You know that no individual in that country lives for 100 or more years. Now, you are given a very si

sort counter 排序

1 2 --------------------对象用Counter------------------------------------------------------------- 3 4 dc={"james":4,"kim":3,"marry":5,"bill":6} 5 from collections import Counter 6 counts=Counter(dc) 7 counts 8 >>

Shell Sort(希尔排序)

近日学习了Shell Sort,也就是希尔排序,也称递减增量排序算法.在1959年由DL.Shell提出于1959年提出,由此得名. 此版本算法是在插入排序(Insertion Sort)基础上,将数组分成了h份(gap).也就是在数组中每隔h个数取出一个数,为一个子数组.先在子数组上进行排序,然后不断减小h的大小,直到h == 1 时,也就是完全变成插入排序的时候,排序完成. 算法复杂度取决于h(步长/步进)的选择,在最差的时候,也就是h == 1的时候,希尔排序就变成了插入排序,复杂度为O(

Spring Data JPA使用Sort进行排序(Using Sort)(转)

通过上一节的学习,我们知道了如何用@Query注解来实现灵活的查询.在上一节的示例中,我也尝试给出简单的排序,通过JPQL语句以及原生SQL来实现的.这样的实现,虽然在一定程度上可以应用,但是灵活度不够,因此结合@Query注解,我们可以使用Sort来对结果进行排序. 1.在CustomerRepository内添加方法 /** * 一个参数,匹配两个字段 * @param name2 * @param sort 指定排序的参数,可以根据需要进行调整 * @return * 这里Param的值和

erlang下lists模块sort(排序)方法源码解析(二)

上接erlang下lists模块sort(排序)方法源码解析(一),到目前为止,list列表已经被分割成N个列表,而且每个列表的元素是有序的(从大到小) 下面我们重点来看看mergel和rmergel模块,因为我们先前主要分析的split_1_*对应的是rmergel,我们先从rmergel查看,如下 ....................................................... split_1(X, Y, [], R, Rs) -> rmergel([[Y, X

HashMap与HashCode有关,用Sort对象排序

遍历Map,使用keySet()可以返回set值,用keySet()得到key值,使用迭代器遍历,然后使用put()得到value值. 上面这个算法的关键语句: Set s=m.keySet(); Interator it=new interator(); Object key=it.next(); Object value=m.get(key); 注意:HashMap与HashCode有关,用Sort对象排序. 如果在HashMap中有key值重复,那么后面一条记录的value覆盖前面一条记录

『ACM C++』HDU杭电OJ | 1425 - sort (排序函数的特殊应用)

今天真的是累哭了,周一课从早八点半一直上到晚九点半,整个人要虚脱的感觉,因为时间不太够鸭所以就回头看看找了一些比较有知识点的题来总结总结分析一下,明天有空了就开始继续打题,嘻嘻嘻. 今日兴趣电影: <超能查派> 这是一部关于未来人工智能的一个故事,感觉特别有思维开拓性,一个程序员写出了真正的AI智能机器人,可以从婴儿开始学习,然后以极快极强的学习速度不断成长,最后拯救身边人的故事.很感人,强烈推荐哈哈~ 爱奇艺:https://www.iqiyi.com/v_19rroly1wo.html?f