给定一个未排序的数组,求其中第k大数。
用分治法的思想,每次从数组中随便取一个数p,将所有大于p的数放在p的左边,其余数放在p的右边,记最终p在数组中的下标为i,则p为数组的第i+1大的数。
若i+1 == k,第k大数即为p,算法结束。
若i+1 < k,第k大数在p的右边,继续在p的右边的数组找第k - i - 1大数。
若i + 1 > k,第k大数在p的左边,继续在p的左边数组找第k大数。
第一个版本我开了额外的数组分别保存比p大和比p小的数,这样的代码简洁且易于理解,但会超空间限制。
class Solution(object): def findKthLargest(self, nums, k): """ :type nums: List[int] :type k: int :rtype: int """ pivot = nums[0] small = [i for i in nums[1:] if i <= pivot] large = [i for i in nums[1:] if i > pivot] if len(large) + 1 == k: return pivot elif len(large) + 1 < k: return self.findKthLargest(small, k - len(large) - 1) else: return self.findKthLargest(large, k)要不使用额外空间,只能修改原来的数组。
class Solution(object): def findKthLargest(self, nums, k): """ :type nums: List[int] :type k: int :rtype: int """ return self.findK(nums, 0, k, len(nums)) def findK(self, nums, start, k, end): pivot = nums[start] last_big = start # 最后一个比p大的数的下标 for i in range(start + 1, end): if nums[i] > pivot: last_big += 1 nums[last_big], nums[i] = nums[i], nums[last_big] nums[last_big], nums[start] = nums[start], nums[last_big] # last_big变为p的下标 if last_big + 1 == k: return pivot elif last_big + 1 > k: return self.findK(nums, start, k, last_big) else: return self.findK(nums, last_big + 1, k, end) # 注意k是不用改变的