diff --git a/solutions/215. Kth Largest Element in an Array.md b/solutions/215. Kth Largest Element in an Array.md new file mode 100644 index 0000000..55700ed --- /dev/null +++ b/solutions/215. Kth Largest Element in an Array.md @@ -0,0 +1,122 @@ +# [215. Kth Largest Element in an Array](https://leetcode.com/problems/kth-largest-element-in-an-array/) + +# 思路 +给定一个数组, 要求返回其中第k大的数. 这应该属于常考的面试题了, 务必掌握. 有两个基本的思路: 快排划分的思想和最大(小)堆. + +时间复杂度平均为O(n) + +## 思路一 +我们回忆一下快排中的partition函数: +每次先(任意)确定一个中枢值pivot,然后遍历其他所有的数字,像这道题从大往小排的话,就把大于中枢点的数字放到左半边, +把小于中枢点的放在右半边,这样中枢点是整个数组中第几大的数字就确定了,虽然左右两部分各自不一定是完全有序的. + +所以我们只需要调用partition函数, +* 若得到pivot的最终位置pos刚好就是k-1, 那直接返回nums[k-1]; +* 若得到的pos比k-1小, 那在pos右边继续调用partition; +* 否则, 在pos左边继续调用partition. + +其实STL中`nth_element`已经帮我们实现了上述过程, 注意学习使用. +**`nth_element`只保证第n(从0开始)个元素是位于最终排序位置的, 但其左右两边的元素则不一定有序.** + + +## 思路二 +用最小堆, 最小堆(实际不是堆是个二叉树)始终保持最小元素在树顶, 那么我们不断去掉top元素知道只剩下k个元素, 那剩下的top元素即所求. +> 或者用最大堆, 这样我们不断去掉k-1个最大堆树顶元素后第k大的元素就位于树顶了. + +在STL中, `priority_queue`和`multiset`都可用来作为最小(大)堆, 代码以前者为例, 用`multiset`可以参考[此处](https://leetcode.com/problems/kth-largest-element-in-an-array/discuss/60309/C%2B%2B-STL-partition-and-heapsort) + +**注意用priority_queue如何实现最大(小)堆, 即如何自定义比较方法(和sort、nth_element、partial_sort函数自定义比较函数写法不一样)** + +其实, STL里有一个函数可以实现部分排序即`partial_sort`, 给定位置k, 该函数会将位置k前(不包含k)的元素排好序, 而k及之后元素则不一定有序. + + +> 建议详读[讨论区总结](https://leetcode.com/problems/kth-largest-element-in-an-array/discuss/60309/C%2B%2B-STL-partition-and-heapsort) + + +# C++ +## 思路一 +``` C++ +class Solution { +private: + int partition(vector &nums, int low, int high){ + int i = low, j = high; + int pivot = nums[low]; + + while(i < j){ + while(i < j && nums[j] < pivot) j--; + nums[i] = nums[j]; // 将比pivot大的元素移到pivot左边 + + while(i < j && nums[i] >= pivot) i++; + nums[j] = nums[i]; // 将比pivot小的元素移到pivot右边 + } + + nums[i] = pivot; + return i; + } +public: + int findKthLargest(vector& nums, int k){ + int low = 0, high = nums.size() - 1, pos; + while(true){ + pos = partition(nums, low, high); + + if(pos == k - 1) return nums[pos]; + if(pos < k - 1) low = pos + 1; + else high = pos - 1; + } + } +}; + +``` + +## 思路一STL版 +``` C++ +class Solution { +public: + int findKthLargest(vector& nums, int k) { + // greater和less都重载了操作符() + nth_element(nums.begin(), nums.begin() + k - 1, nums.end(), greater()); + return nums[k - 1]; + } +}; +``` + +## 思路二 +``` C++ +class Solution { +static bool comp_func(const int &a, const int &b){ + return a > b; +} +struct comp_class{ + bool operator()(const int &a, const int &b){ + return a > b; + } +}; +public: + int findKthLargest(vector& nums, int k){ + // 以下三种写法都是可以的. 默认为最大堆: priority_queue > pq; + // priority_queue, greater> pq; + // priority_queue, bool (*)(const int &a, const int &b) > pq(comp_func); + priority_queue, comp_class > pq; + + for (int num : nums) { + pq.push(num); + if (pq.size() > k) { + pq.pop(); + } + } + return pq.top(); + } +}; + +``` + +## 思路二STL版 +``` C++ +class Solution { +public: + int findKthLargest(vector& nums, int k) { + partial_sort(nums.begin(), nums.begin() + k, nums.end(), greater()); + return nums[k - 1]; + } +}; +```