博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[LeetCode] Kth Largest Element in an Array
阅读量:6956 次
发布时间:2019-06-27

本文共 6431 字,大约阅读时间需要 21 分钟。

Well, this problem has a naive solution, which is to sort the array in descending order and return the k-1-th element. However, sorting algorithm gives O(nlogn) complexity. Suppose n = 10000and 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 becomeT(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.

1 class Solution {  2 public: 3     int partition(vector
& nums, int left, int right) { 4 int pivot = nums[left]; 5 int l = left + 1, r = right; 6 while (l <= r) { 7 if (nums[l] < pivot && nums[r] > pivot) 8 swap(nums[l++], nums[r--]); 9 if (nums[l] >= pivot) l++;10 if (nums[r] <= pivot) r--;11 }12 swap(nums[left], nums[r]);13 return r;14 }15 int findKthLargest(vector
& nums, int k) {16 int left = 0, right = nums.size() - 1;17 while (true) {18 int pos = partition(nums, left, right);19 if (pos == k - 1) return nums[pos];20 if (pos > k - 1) right = pos - 1;21 else left = pos + 1;22 }23 }24 };

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) withnums[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 atnums[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 :-)

1 class Solution { 2 public:  3     inline int parent(int idx) { 4         return (idx - 1) >> 1; 5     } 6     inline int left(int idx) { 7         return (idx << 1) + 1; 8     } 9     inline int right(int idx) {10         return (idx << 1) + 2;11     }12     void max_heapify(vector
& nums, int idx) {13 int largest = idx;14 int l = left(idx), r = right(idx);15 if (l < heap_size && nums[l] > nums[largest]) largest = l;16 if (r < heap_size && nums[r] > nums[largest]) largest = r;17 if (largest != idx) {18 swap(nums[idx], nums[largest]);19 max_heapify(nums, largest);20 }21 }22 void build_max_heap(vector
& nums) {23 heap_size = nums.size();24 for (int i = (heap_size >> 1) - 1; i >= 0; i--)25 max_heapify(nums, i);26 }27 int findKthLargest(vector
& nums, int k) {28 build_max_heap(nums);29 for (int i = 0; i < k; i++) {30 swap(nums[0], nums[heap_size - 1]);31 heap_size--;32 max_heapify(nums, 0);33 }34 return nums[heap_size];35 }36 private:37 int heap_size;38 }

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

1 class Solution {2 public:3     int findKthLargest(vector
& nums, int k) {4 priority_queue
pq(nums.begin(), nums.end());5 for (int i = 0; i < k - 1; i++)6 pq.pop(); 7 return pq.top();8 }9 };

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

1 class Solution { 2 public: 3     int findKthLargest(vector
& nums, int k) { 4 multiset
mset; 5 int n = nums.size(); 6 for (int i = 0; i < n; i++) { 7 mset.insert(nums[i]); 8 if (mset.size() > k) 9 mset.erase(mset.begin());10 }11 return *mset.begin();12 }13 };

 

转载地址:http://matil.baihongyu.com/

你可能感兴趣的文章
[译]在 React.js 中使用 ES6+
查看>>
协同过滤算法
查看>>
移动端原生JS实现手指跟随的触控滑动
查看>>
js初级应用之svg实现环形进度条
查看>>
ASP.NET CORE下运行CMD命令
查看>>
requests库核心API源码分析
查看>>
C语言程序员不会告诉你的14个工具和插件 | 收藏 ...
查看>>
2019年人工智能硬件与应用大趋势
查看>>
2018 FDA获批医疗器械盘点,政策红利能否继续?
查看>>
Git协同工作流介绍
查看>>
语音识别实时对比(百度收费 VS SpeechTexter免费)
查看>>
2018智能汽车盘点,新旧造车势力的智能化PK
查看>>
阿里云服务器的配置及搭建教程
查看>>
书籍:python游戏编码 Coding Games in Python - 2018
查看>>
Docker镜像细节
查看>>
如何通过脚本实现数据动态更新
查看>>
远禾科技出席阿里ASRC生态大会 并参与安恒西湖论剑
查看>>
使用eclipse创建web项目的项目图文步骤
查看>>
window powershell 获取所有用户的最后登录时间
查看>>
ApiPost的环境变量的定义和使用「ApiPost环境变量」
查看>>