题目来源:Leetcode 215 数组中第K个最大的元素
题目描述:
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例 1:
输入: [3,2,1,5,6,4] 和
k = 2
输出: 5
1.排序方法
复杂度为O(nlogn),可以直接调用python的排序函数做(用时52ms):
class Solution:
def findKthLargest(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
nums.sort()
return nums[-k]
自己手写快排(用时284ms,咋这么慢。。。):
class Solution:
def findKthLargest(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
import random
self.quickSort(nums, 0, len(nums) - 1)
return nums[-k]
def partation(self, nums, l, r):
"""随机partation"""
change_index = random.randint(l, r)
nums[change_index], nums[r] = nums[r], nums[change_index]
num = nums[r]
less_index = l - 1
more_index = r + 1
p = l
while p < more_index:
if nums[p] < num:
less_index += 1
nums[p], nums[less_index] = nums[less_index], nums[p]
p += 1
elif nums[p] == num:
p += 1
else:
more_index -= 1
nums[p], nums[more_index] = nums[more_index], nums[p]
equal_area = [less_index + 1, more_index - 1]
return equal_area
def quickSort(self, nums, l, r):
if r - l < 1:
return
else:
eq_area = self.partation(nums, l, r)
self.quickSort(nums, l, eq_area[0] - 1)
self.quickSort(nums, eq_area[1] + 1, r)
2.选择方法
定义一个存放最大值的集合set,每遍历一次数组,找到一个不在集合中的最大数,返回第k次遍历结果,这个方法超过时了。
def findKthLargest(nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
num_set = set()
p = 0
while p < k:
cur_max = -float('inf')
for i in nums:
if i not in num_set and i > cur_max:
cur_max = i
count = 0
if i == cur_max:
count += 1
num_set.add(cur_max)
p += count
return cur_max
3.堆
建立一个包括k个数小根堆,遍历数组,如果大于小根堆的堆顶,替换,重新构建小根堆。
python自带的堆实现(52ms):
def findKthLargest(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
import heapq
return heapq.nlargest(k, nums)[-1]
不调用库,自己实现(112ms):
主要解决两个问题:创建堆,堆顶元素改变维
def findKthLargest(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
#先将前k个数变成小根堆
nums = self.heapInsert(nums, k)
for i in range(k, len(nums)):
if nums[i] > nums[0]:
nums = self.heapify(nums, nums[i], k)
return nums[0]
def heapInsert(self, nums, k):
"""
将列表转变为小根堆
"""
for index in range(1, k):
while nums[(index - 1) // 2] > nums[index] and index > 0:
nums[(index - 1) // 2], nums[index] = \
nums[index], nums[(index - 1) // 2]
index = (index - 1) // 2
return nums
def heapify(self, nums, new_val, k):
"""
小根堆nums的堆顶变成new_val,重新生成小根堆
"""
head = 0
nums[head] = new_val
l = 1
while l < k:
r = l + 1
if r >= k:
small = l
else:
if nums[l] <= nums[r]:
small = l
else:
small = r
if nums[head] < nums[small]:
break
nums[head], nums[small] = nums[small], nums[head]
head = small
l = head * 2 + 1
return nums
4.快速选择
利用快排的思想(这个用了3000多ms,不知道为啥这么慢。。)
class Solution:
def findKthLargest(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
#这里得到的是最大的k个数字,可能是不是有序的
topk_nums = sorted(self.partation(nums, 0, len(nums) - 1, k))
return topk_nums[-k]
def partation(self, nums, left, right, k):
"""
大->中->小
"""
if right <= left:
return nums[:k]
l = left - 1
r = right + 1
num = nums[right]
p = left
while p < r:
if nums[p] == num:
p += 1
elif nums[p] > num:
l += 1
nums[p], nums[l] = nums[l], nums[p]
p += 1
else:
r -= 1
nums[r], nums[p] = nums[p], nums[r]
if k <= l:
return self.partation(nums, left, l, k)
elif k >= r:
return self.partation(nums, r, right, k)
else:
return nums[:k]
5.插入排序
前k个数字变成一个有序的序列(范围:0 ~ k - 1,从大到小),遍历后面的数字,每次遍历,将其插入到前k个数字中对应的位置(60ms)
class Solution:
def findKthLargest(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
topk_nums = nums[:k]
topk_nums.sort()
for i in range(k, len(nums)):
if nums[i] > topk_nums[0]:
insert_index = self.searchInsert(topk_nums, nums[i])
topk_nums.insert(insert_index, nums[i])
topk_nums.pop(0)
return topk_nums[-k]
def searchInsert(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
if target <= nums[0]:
return 0
if target > nums[-1]:
return len(nums)
l, r = 0, len(nums) - 1
while r >= l:
mid = (l + r) // 2
if nums[mid] == target:
return mid
elif nums[mid] > target:
if nums[mid - 1] < target:
return mid
else:
r = mid - 1
else:
if nums[mid + 1] > target:
return mid + 1
else:
l = mid + 1