「这是我参与2022首次更文挑战的第30天,活动详情查看:2022首次更文挑战」。
1.题目
排序数组
给你一个整数数组 nums,请你将该数组升序排列。
示例 1:
输入:nums = [5,2,3,1]
输出:[1,2,3,5]
示例 2:
输入:nums = [5,1,1,2,0,0]
输出:[0,0,1,1,2,5]
提示:
1 <= nums.length <= 5 * 104
-5 * 104 <= nums[i] <= 5 * 104
思路
任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两个子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后左右子序列重复该过程,直到所有元素都排在相应位置上为止。
基本思路:快速排序每一次都排定一个元素(这个元素呆在了它最终应该呆的位置),然后递归地去排它左边的部分和右边的部分,依次进行下去,直到数组有序;
算法思想:分而治之(分治思想),与「归并排序」不同,「快速排序」在「分」这件事情上不想「归并排序」无脑地一分为二,而是采用了 partition 的方法(书上,和网上都有介绍,就不展开了),因此就没有「合」的过程。
实现细节(注意事项):(针对特殊测试用例:顺序数组或者逆序数组)一定要随机化选择切分元素(pivot),否则在输入数组是有序数组或者是逆序数组的时候,快速排序会变得非常慢(等同于冒泡排序或者「选择排序」);
时间复杂度:基于随机选取主元的快速排序时间复杂度为期望 O(n\log n)O(nlogn),其中 nn 为数组的长度。
空间复杂度:O(h)O(h),其中 hh 为快速排序递归调用的层数。我们需要额外的 O(h)O(h) 的递归调用的栈空间,由于划分的结果不同导致了快速排序递归调用的层数也会不同,最坏情况下需 O(n)O(n) 的空间,最优情况下每次都平衡,此时整个递归树高度为 \log nlogn,空间复杂度为 O(\log n)O(logn)。
代码
var sortArray = function(nums) {
// 单独开辟两个存储空间left和right来存储每次递归比target小和大的序列
// 每次递归直接返回left、target、right拼接后的数组
if (nums.length < 2) return nums
const target = nums[0]
const left = []
const right = []
for (let i = 1;i<nums.length;i++) {
if (nums[i] < target) {
left.push(nums[i])
} else {
right.push(nums[i])
}
}
return sortArray(left).concat([target], sortArray(right))
};