912. 排序数组(Sort an Array)
频次 ★★★★★ · 难度 🟡 · 高频:字节/阿里/美团
题目
升序排序整数数组,用快排实现(面试中最常要求写的就是快排)。
思路
快速排序(三路切分优化):选 pivot,将数组分为 < pivot、== pivot、> pivot 三部分,递归处理前后两部分。三路切分对大量重复元素友好(退化为 O(n) 而非 O(n²))。
代码
public int[] sortArray(int[] nums) {
quickSort(nums, 0, nums.length - 1);
return nums;
}
private void quickSort(int[] nums, int l, int r) {
if (l >= r) return;
// 随机选 pivot,避免最坏 O(n²)
int idx = l + (int)(Math.random() * (r - l + 1));
swap(nums, idx, r); // 放到最右边
int[] p = partition(nums, l, r); // 三路切分
quickSort(nums, l, p[0] - 1);
quickSort(nums, p[1] + 1, r);
}
// 返回 < pivot 的右边界和 > pivot 的左边界
private int[] partition(int[] nums, int l, int r) {
int pivot = nums[r];
int i = l, lt = l, gt = r;
while (i <= gt) {
if (nums[i] < pivot) swap(nums, i++, lt++);
else if (nums[i] > pivot) swap(nums, i, gt--);
else i++;
}
return new int[]{lt, gt};
}
private void swap(int[] nums, int i, int j) {
int t = nums[i]; nums[i] = nums[j]; nums[j] = t;
}复杂度
- 时间:平均 O(n log n),最坏 O(n²)
- 空间:O(log n) —— 递归栈
边界条件
- 空数组/单元素:直接返回
- 全相同元素:三路切分一次完成,O(n)
变式
- 归并排序:稳定的 O(n log n),需 O(n) 辅助空间
- 堆排序:O(n log n) 原地排序
- 215. 数组中的第K大:快排的 partition 思想
易错点
- 随机选 pivot 不能省略——有序数组每次选最右是最坏 O(n²)
- 三路切分中
i只在nums[i] < pivot时前进,nums[i] > pivot时只交换不前进(因为换过来的数还没比较过) - 桶排序/计数排序只适合小范围整数
面试追问
- 快排最坏情况怎么避免? 随机选 pivot、三路切分、或切换到插入排序(小数组)
- 快排和归并排序的应用场景? 快排原地排序适合数组;归并稳定、适合链表