-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
208 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
--- | ||
title: 算法-排序与双指针 | ||
date: 2024-08-23 21:52:10 | ||
categories: | ||
- 数据结构与算法 | ||
tags: | ||
- js | ||
- 算法 | ||
cover: https://assets.leetcode.cn/aliyun-lc-upload/uploaded_files/2021/03/73c9f099-abbe-4d94-853f-f8abffd459cd/leetcode.png | ||
--- | ||
|
||
## 排序 | ||
|
||
O(n^2)的排序算法:冒泡,选择,插入 | ||
O(nlogn)的排序算法:快排,归并 | ||
O(n)的排序算法:桶排序,计数排序,基数排序 | ||
|
||
### 冒泡排序 | ||
1.第一轮,相邻的两个两两比较,把最小的冒泡到第1个 | ||
2.第二轮,相邻的两个两两比较,把第二小的冒泡到第2个 | ||
3.重复len-1轮 | ||
|
||
```js | ||
function bubbleSort(arr) { | ||
for (let i = 0; i < arr.length - 1; i++) { | ||
for (let j = arr.length - 1; j > i; j--) { | ||
if (arr[j - 1] > arr[j]) { | ||
[arr[j - 1], arr[j]] = [arr[j], arr[j - 1]] | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
|
||
或者反过来想,把最大的冒泡到最后面 | ||
```js | ||
function bubbleSort(arr) { | ||
for (let i = arr.length - 1; i > 1; i--) { | ||
for (let j = 0; j < i; j++) { | ||
if (arr[j] > arr[j + 1]) { | ||
[arr[j + 1], arr[j]] = [arr[j], arr[j + 1]] | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
|
||
### 选择排序 | ||
1.第一轮,选取最小的放到第1个 | ||
2.第二轮,选取第二小的放到第2个 | ||
3.重复len-1轮 | ||
|
||
```js | ||
function selectSort(arr) { | ||
for(let i=0;i<arr.length-1;i++) { | ||
let minIndex = i; | ||
for(let j=i+1;j<arr.length;j++) { | ||
if(arr[j]<arr[minIndex]) { | ||
minIndex = j | ||
} | ||
} | ||
if(minIndex!==i) { | ||
[arr[i], arr[minIndex]] = [arr[minIndex], arr[i]] | ||
} | ||
} | ||
} | ||
``` | ||
|
||
### 插入排序 | ||
1. 从第2个开始,往前找,如果一直是大于这个数的,把这些数往后移,最后插入这个数 | ||
2. 从第3个,重复这个过程(len-1轮) | ||
|
||
```js | ||
function insertSort(arr) { | ||
for (let i = 1; i < arr.length; i++) { | ||
let currentVal = arr[i] | ||
let j = i - 1 // j是需要插入的位置的前一个位置 | ||
while (j >= 0) { | ||
if (arr[j] > currentVal) { | ||
arr[j + 1] = arr[j] | ||
j-- | ||
} else { | ||
break; | ||
} | ||
} | ||
arr[j + 1] = currentVal | ||
} | ||
} | ||
``` | ||
|
||
### 快速排序 | ||
1.从数组中选取一个作为pivot,把小于等于pivot的移到左边,把大于pivot的移到右边 | ||
2.继续快速排序左边的和右边的 | ||
|
||
```js | ||
// 非原地排序版本 | ||
function quickSort(arr) { | ||
|
||
if(arr.length <= 1) return arr; | ||
|
||
const pivotIndex = Math.floor(Math.random(0, arr.length)); | ||
const pivot = arr[pivotIndex]; | ||
|
||
let left = arr.filter((item,index)=>item<=pivot && index!==pivotIndex); | ||
let right = arr.filter((item)=>item>pivot); | ||
|
||
return [...quickSort(left), pivot, ...quickSort(right)] | ||
} | ||
``` | ||
|
||
```js | ||
// 原地排序版本 | ||
function quickSort(arr) { | ||
|
||
function q(arr, low, high) { | ||
|
||
if(high-low<=0) return; | ||
|
||
const pivotIndex = low + Math.floor(Math.random(0, high+1)); | ||
const pivot = arr[pivotIndex]; | ||
|
||
let i=low,j=high | ||
while(true) { | ||
while(arr[i]<=pivot) { | ||
i++ | ||
} | ||
|
||
while(arr[j]>pivot) { | ||
j-- | ||
} | ||
|
||
if(i>=j) break; | ||
|
||
[arr[i], arr[j]] = [arr[j], arr[i]] | ||
i++ | ||
j-- | ||
} | ||
// 把pivot放到合适的位置上 | ||
[arr[pivotIndex] , arr[j]] = [arr[j], arr[pivotIndex]] | ||
|
||
q(arr, low, j - 1) | ||
q(arr, j + 1, high) | ||
} | ||
|
||
q(arr, 0 ,arr.length - 1) | ||
} | ||
``` | ||
|
||
### 归并排序 | ||
1.排序左边的,排序右边的 | ||
2.合并两个有序数组 | ||
|
||
```js | ||
function mergeSort(arr) { | ||
if (arr.length <= 1) return arr; | ||
|
||
let mid = (arr.length >> 1) - 1; // 这里不减一的话数组长度为2时会无限递归 | ||
|
||
const left = mergeSort(arr.slice(0, mid + 1)) | ||
const right = mergeSort(arr.slice(mid + 1)) | ||
|
||
function merge(arr1, arr2) { | ||
let res = [] | ||
let i = 0, j = 0 | ||
|
||
while (i < arr1.length && j < arr2.length) { | ||
if (arr1[i] < arr2[j]) { | ||
res.push(arr1[i++]) | ||
} else { | ||
res.push(arr2[j++]) | ||
} | ||
} | ||
|
||
if (i < arr1.length) { | ||
res = res.concat(arr1.slice(i)) | ||
} | ||
if (j < arr2.length) { | ||
res = res.concat(arr2.slice(j)) | ||
} | ||
|
||
return res; | ||
} | ||
|
||
return merge(left, right) | ||
} | ||
``` | ||
|
||
### 桶排序 | ||
按照一定的算法分为n个桶,使数字能较为均匀的分布到n个桶中。 | ||
如第1个桶放小于10的,第2个桶放10~20的 | ||
然后对每个桶进行排序,最后按顺序合并每个桶得到最终的结果。 | ||
|
||
### 计数排序 | ||
计数排序时特殊的桶排序。 | ||
比如说分数是0~100分,那么就分101个桶。 | ||
|
||
### 基数排序 | ||
只能排序非负整数。 | ||
比如说十进制的数,先按个位数排序,再按十位数排序。 | ||
|
||
## 双指针 | ||
|
||
1. 环形链表:https://leetcode.cn/problems/linked-list-cycle-ii/description/ | ||
两个指针,一个指针一次前进1,一个指针1次前进2;如果有环,这两个指针一定会相遇 | ||
2. 返回arr的最长无重复子数组的长度:https://leetcode.cn/problems/longest-substring-without-repeating-characters/description/ | ||
3. 最长上升子序列: https://leetcode.cn/problems/longest-increasing-subsequence/description/ | ||
4. 盛水最多的容器: https://leetcode.cn/problems/container-with-most-water/description/ | ||
5. 三数之和:https://leetcode.cn/problems/3sum/description/ |