# 215. Kth Largest Element in an Array

**<font color=red>难度: Medium</font>**

## 刷题内容

> 原题连接

* https://leetcode.com/problems/kth-largest-element-in-an-array/description/

> 内容描述

```
Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.

Example 1:

Input: [3,2,1,5,6,4] and k = 2
Output: 5
Example 2:

Input: [3,2,3,1,2,4,5,5,6] and k = 4
Output: 4
Note: 
You may assume k is always valid, 1 ≤ k ≤ array's length.
```

## 解题方案

> 思路 1
******- 时间复杂度: O(NlgN)******- 空间复杂度: O(N)******

先全部放到一个最大堆中去，然后返回第k个就行了

因为python实现的heapq插入操作的时间复杂度是O(lgN)，所以最终时间复杂度是O(NlgN)

```
1. bisect
根据insort_left 的文档：

Keep in mind that the O(log n) search is dominated by the slow O(n) insertion step.

也就是说，单次 insort_left 的时间复杂度是 O(n)，自然 sort1 的复杂度就变成了 O(n^2)，它最慢是应当的。

2. sort
文档说是 O(n log n) 的复杂度。从 listsort 详细文档来看，开发人员着实没少下了工夫。

3. heappush
根据维基百科，插入操作的时间复杂度是 O(log n)，所以总的时间复杂度仍然是 O(n log n)。不过有一点值得注意，插入操作的平均时间是 O(1)，所以有可能会稍微快一点。

Python vs. PyPy
CPython 2.7

sort1 : bisect 2.617674
sort2 :lst.sort 0.295187
sort3 : heapq 0.39279
PyPy 2.4

sort1 : bisect 1.31
sort2 :lst.sort 0.043
sort3 : heapq 0.029
注，我把你的调用部分复制了一遍，执行了两次，结果为第二次的输出。

可以看得出，O(n log n) 算法的耗时是在同一个数量级上的，但 CPython 中 sort 胜出，PyPy 中 heapq　胜出。
```

详细可见：
1. [heapq数据结构](https://love.ranshy.com/heapq-%E5%A0%86%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/)
2. [序列的sort方法 与 bisect.insort, heapq.heappush 效率比较](https://segmentfault.com/q/1010000000664272)


```python
class Solution(object):
    def findKthLargest(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        from heapq import heappush, heappop
        topk = []
        heap = []
        for i in range(len(nums)):
            heappush(heap, -nums[i])
        for i in range(k):
            if i == k-1:
                return -heappop(heap)
            heappop(heap)
```


> 思路 2
******- 时间复杂度: O(Nlgk)******- 空间复杂度: O(k)******

前面的思路是全部放进去以后再pop k次

现在打算只维护一个容量为k的最大堆，最终堆顶的值就是结果


```python
class Solution(object):
    def findKthLargest(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        if not nums: 
            return 0
        from heapq import *
        heap = []
        for i in range(len(nums)):
            heappush(heap,nums[i])
            if len(heap) > k:
                heappop(heap)
        return heap[0]
```



> 思路 3
******- 时间复杂度: O(N)******- 空间复杂度: O(n)******

二分+quick sort的思想，随机取一个pivot，大于小于等于它的分别放起来，然后看看大于它的有没有k个，没有就可能在等于或者小于里面

二分是O(lgN),但是找大于小于等于是O(N)，所以最终时间复杂度是O(N)

```python
class Solution(object):
    def findKthLargest(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        pivot = nums[0]
        smaller  = [num for num in nums if num < pivot]
        equal = [num for num in nums if num == pivot]
        greater = [num for num in nums if num > pivot]
        
        if len(greater) >= k:
            return self.findKthLargest(greater, k) #k may be there
        elif len(equal) >= (k - len(greater)): # k may be in equal or smaller
            return equal[0] # any number from equal
        else:
            return self.findKthLargest(smaller, k - len(greater) - len(equal))
```

