Skip to content

Commit

Permalink
feat: 算法-排序与双指针
Browse files Browse the repository at this point in the history
  • Loading branch information
duanlvxin committed Aug 25, 2024
1 parent e334c9e commit 976df4a
Showing 1 changed file with 208 additions and 0 deletions.
208 changes: 208 additions & 0 deletions source/_posts/算法-排序与双指针.md
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/

0 comments on commit 976df4a

Please sign in to comment.