https://labuladong.github.io/algo/di-yi-zhan-da78c/shou-ba-sh-66994/kuai-su-pa-39aa2/
先看核心代码
def sort(nums, lo, hi):
if (lo >= hi):
return
p = partition(nums, lo, hi)
sort(nums, lo, p-1)
sort(nums, p+1, hi)
一句话总结快排:先将一个元素排好序(nums[p]),再将剩下的元素排好序
快排的核心是partition函数,其作用是在nums[lo, …, hi]中寻找一个切分点索引p, 让nums[lo,...,p] <= nums[p] < nums[p+1, ..., hi]
,注意这里的边界条件,是小于等于和大于。即把nums[p]放到正确的位置上;再用递归把左边和右边的部分都排好序即可,其实就是一个二叉树的前序遍历。
partition函数的结果类似一个二叉搜索树,nums[p]
是根节点,左边是左子树,右边是右子树。或者说,快排就是一个构造二叉搜索树的过程。
但是有可能会碰到极端不平衡的情况,比如每次选出的p都在两端,导致左子树或者右子树为空,这样时间复杂度会大幅度上升,因此需要增加数组的随机性。
class Solution(object):
def quickSort(self, nums, lo, hi):
if (lo >= hi):
return
p = self.partition(nums, lo, hi)
self.quickSort(nums, lo, p-1)
self.quickSort(nums, p+1, hi)
def partition(self, nums, lo, hi):
import random
pivot_idx = random.randint(lo, hi)
self.swap(nums, lo, pivot_idx) # 随机选择pivot
pivot = nums[lo]
i, j = lo+1, hi
while i <= j:
while i < hi and nums[i] <= pivot:
i += 1
while j > lo and nums[j] > pivot:
j -= 1
if (i >= j):
break
self.swap(nums, i, j)
self.swap(nums, lo, j)
return j
def swap(self, nums, i, j):
nums[i], nums[j] = nums[j], nums[i]
def sortArray(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
self.quickSort(nums, 0, len(nums)-1)
return nums
以上方法是传统的两路快排,缺点是leetcode上有个[2,2,2,2…]的相同元素case过不了(官方的c++题解都过不了)。这里可以用以下三路排序的方式来解决,把整个数组分成
代码如下