前言
按照重点掌握程度列个表,其他的算法就先不用管了
算法 | 程度要求 | 时间复杂度 | 空间复杂度 | 稳定性 |
---|---|---|---|---|
快速排序 | 重点掌握 | O(nlogn) | O(logn) | 不稳定 |
归并排序 | 重点掌握 | O(nlogn) | O(n) | 稳定 |
堆排序 | 熟悉 | O(n2) | O(1) | 不稳定 |
冒泡排序 | 了解 | O(n2) | O(1) | 稳定 |
选择排序 | 了解 | O(n2) | O(1) | 不稳定 |
快速排序
快排是必考的,思路如下,b站一个up讲得挺清晰的
- 三个指针,left,right和pivot,每次pivot取一个值(假设都取数组首位),left、right都和pivot进行比较;
- right > pivot , 就 right-- ,否则就让right位置的值移到pivot位置上,即小的都移到左边;
- right操作完后,left进行同样操作
- 左右指针相互进行,如果rigth指针的值一直大于pivot的值,那么指针就一直–,直到left >= right
- 该轮排序结束,pivot的左边都比它小,右边都比它大,然后进行递归
时间复杂度:
- 因为有递归,并且是每次二分的进行递归,所以算是logn
- 每一次递归中,left都会和right相遇,所以是走遍了整个数组,所以是n
- 总的加起来就是 nlogn
空间复杂度:
- 因为有递归,所以跟递归相关,是 logn
参考题目
本人的快排做法
/**
* @param {number[]} nums
* @return {number[]}
*/
var sortArray = function (nums) {
const quickSort = (nums, L, R)=>{
if (L >= R) return
let l = L
let r = R
let pivot = nums[l]
while (l < r) {
while (l < r && nums[r] >= pivot) {
r--
}
if (l < r) {
nums[l] = nums[r]
}
while (l < r && nums[l] <= pivot) {
l++
}
if (l < r) {
nums[r] = nums[l]
}
if (l >= r) {//这里其实可以放到while循环之外的,当时没想到
nums[l] = pivot
}
}
quickSort(nums,L,l-1)
quickSort(nums,l+1,R)
}
quickSort(nums,0,nums.length-1)
return nums
};
后来再看,不够简洁,性能不高,看了看大神的算法,如下
/**
* @param {number[]} nums
* @return {number[]}
*/
var sortArray = function (nums) {
const swap = (arr, i, j) => {
[arr[i], arr[j]] = [arr[j], arr[i]]
}
const _quickSort = (arr, left, right) => {
if (left >= right) {
return
}
let o = left
let i = left, j = right
while (left !== right) {
// 先从右往左动
while (arr[right] >= arr[o] && left < right) {
right--
}
while (arr[left] <= arr[o] && left < right) {
left++
}
if (left < right) {
swap(arr, left, right)
}
}
swap(arr, o, left)
_quickSort(arr, i, left - 1)
_quickSort(arr, left + 1, j)
}
_quickSort(nums, 0, nums.length - 1)
return nums
};
但是,这个运算时间却更慢。。。
归并排序
也是利用递归,在每次递归里面,进行 left — mid 和 mid+1 — right 两段数组的比较(都从头开始比)
时间复杂度同样是 nlogn
但是空间复杂度因为用到了ans数组,所以是 n
/**
* @param {number[]} nums
* @return {number[]}
*/
var sortArray = function(nums) {
return mergeSort(nums, 0, nums.length - 1)
};
//递归,如此会细分到长度只有2的数组才开始
function mergeSort(nums, left, right) {
//只要index左边超过右边就说明到底了
if (left >= right) return nums;
//算出mid的index
let mid = (left + right) >> 1;
//连续递归下去,能细分个数为2的层次,然后进行merge,排完最低层次后,再return回上一层,递归回去排序上一层
mergeSort(nums, left, mid)
mergeSort(nums, mid + 1, right)
return merge(nums, left, mid, right)
}
//比较每一次递归里面的两个分段,然后合并
function merge(nums, left, mid, right) {
//用于记录,完了会滕到原数组里面,相当于temp
let ans = [];
//分出两段的起始
let c = 0, i = left, j = mid + 1;
//如果比较的指针两段都还没走完,这个指针可能是i也可能是j
while (i <= mid && j <= right) {
//谁小就放到ans中
if (nums[i] < nums[j]) {
ans[c++] = nums[i++];
} else {
ans[c++] = nums[j++]
}
}
//到这里就说明,至少有一段已经走完了,把剩下的另一段的,全部放进ans后面就行,都是有序的,因为是从长度2的数组开始合并的
while (i <= mid) {
ans[c++] = nums[i++];
}
while (j <= right) {
ans[c++] = nums[j++];
}
//把ans放进nums原数组,并返回nums
for (let i = 0; i < ans.length; i++) {
nums[i + left] = ans[i];
}
return nums;
}
作者:jsyt
链接:https://leetcode-cn.com/problems/sort-an-array/solution/5chong-chang-yong-pai-xu-suan-fa-by-jsyt/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。