- 冒泡算法
基本思想:重复遍历要排序的数组,每次比较相邻两个元素的大小,如果顺序错误,则交换两个元素的位置
步骤:
1.比较相邻两个元素,如果位置不对交换两个元素
2.对每一对相邻的元素重读步骤1,直到最后,把最大(小)元素冒泡的最后一个位置
3.针对所有(除最后一个)元素,重复步骤1,2
重复步骤1,2,3,直到排序完成
function bubbleSort (arr) {
let len = arr.length;
for(let i=0; i<len; i++) {
for(let j=0; j<len-1-i;j++) {
if(arr[j]>arr[j+1]) {
[arr[j],arr[j+1]] = [arr[j+1], arr[j]];
}
}
}
return arr;
}
let arr = [2, 9, 30,10, 17, 31, 28, 5];
bubbleSort(arr)
2.快速排序
基本思想:他是一种分而治之的算法,找出一个参考值,通过递归的方式将数据一次分解为包含较小元素和较大元素的
不同子序列,重复这个步骤直到所有数据都是有序的
步骤:
1. 选择一个参考元素,将数组分割为两个子序列
2. 对序列重新排序,将所有小于基准的元素放在基准值的前面,大于基准值的元素放在基准值的右侧
3. 分别对小元素的子序列和较大元素的子序列重复步骤1,2
function quickSort (arr) {
let len=arr.length,left=[],right=[],current = arr[0];
if(len<=1) return arr;
for(let i=1; i<len; i++){
if(arr[i]<current) {
left.push(arr[i]);
} else {
right.push(arr[i])
}
}
// 递归步骤1,2
return quickSort(left).concat(current, quickSort(right))
}
3.插入排序
基本思想:通过构建有序序列,对于未排序数据,在已排序的队列中从后向前扫描,找到相应的位置并插入。
步骤:
1. 从第一个元素开始,该元素被认为是已经排序
2. 取出下一个与元素,在已经排序的队列中从后向前扫描
3. 如果该元素(已排序)大于新元素,将元素移到下一个位置
4. 重复步骤3,直到找到已排序元素中小于或等于新元素的位置
5. 将新元素插入到这个位置
6. 重复步骤2~5
/**双层循环,外循环控制未排序的元素,内循环控制已排序的元素,将未排序元素设为标杆,
与已排序的元素进行比较,小于则交换位置,大于则位置不动
*/
function insertSort(arr) {
let tem
for(let i=0; i<arr.length; i++) {
tem = arr[i]
for(let j=i; j>=0; j--){
if(arr[j-1] > tem){
arr[j] = arr[j-1]
} else {
arr[j] = tem
break
}
}
}
return arr
}
4.选择排序
基本思想:首先在待排序的序列中选出最大值(或最小值),存放在排序序列的起始位置,然后再从剩余未排序的序列
中继续选出最大值(或最小值),放在已排序的队列的末尾,以此类推,直到所有元素排序完成。
步骤:
1. 初始状态:无序区为[1,...,n], 有序区为空
2. 第i(i=1,2,3...n)趟排序时,当前有序区和无需区分别为[1, ...,i-1]和[i,...,n], 该趟排序从无序列表中选出
最小(大)的元素,将它与无需区的第一个元素交换
3. n-1趟结束后,数组就是有序的了
/**
* 先假设第一个元素为最小的,然后通过循环找出最小元素,
* 然后同第一个元素交换,接着假设第二个元素,重复上述操作即可
*/
function selectSort(arr) {
let len = arr.length, minIndex, tem
for(let i=0; i<len-1; i++) {
minIndex = i //最小值下标
for(let j=i+1; j<len; j++) {
if(arr[j] < arr[minIndex]){
// 找出最小值
minIndex = j //更换最小值下标
}
}
// 交换位置
tem = arr[i]
arr[i] = arr[minIndex]
arr[minIndex] = tem
}
return arr
}
5.归并排序
基本思想:将若干有序序列逐步归并,最终归并为一个有序序列。
步骤:
1. 把长度为n的序列分成两个长度为n/2的子序列
2. 对这两个子序列分别采用归并排序
3. 将排好序的子序列合并成最终的有序序列
// 将数组一直等分,然后合并
function merge(left, right) {
let tem = [];
while(left.length && right.length) {
if(left[0] < right[0]) {
tem.push(left.shift());
}else{
tem.push(right.shift());
}
}
return tem.concat(left,right);
}
function mergeSort(arr) {
const len = arr.length;
if(len<2) return arr;
let mid = Math.floor(len / 2), left = arr.slice(0,mid), right = arr.slice(mid);
return merge(mergeSort(left),mergeSort(right));
}
6.希尔排序
基本思想:把记录按的一定增量分组,对每组使用直接插入排序,随着增量的逐步减少,每组包含的元素越来越多,当增
量减少到1时,整个序列被分成一组,排序完成。
步骤:
1.选择一个增量序列t1,t2,t3…tk, 其中ti>tj,tk=1
2.按增量序列个数k,对序列进行k趟排序
3.每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量
因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度
function shellSort(arr) {
var len = arr.length;
for(var gap = Math.floor(len / 2); gap > 0; gap = Math.floor(gap / 2)) {
for(var i = gap; i < len;i++) {
var j = i;
var current = arr[i];
while (j - gap >= 0 && current < arr[j - gap]) {
arr[j] = arr[j - gap];
j = j - gap;
}
arr[j] = current;
}
}
return arr;
}
- 数组翻转
// [].reverse()
let arr = [2, 9, 30, 17, 31, 28, 5];
for (let i = 0; i < arr.length / 2; i++) {
let num = arr[i];
arr[i] = arr[arr.length -1 - i];
arr[arr.length -1 - i] = num;
}
8.数组去重
// [...new Set(arr)]
let arr = [1,2,3,4,5,3,2,4,1];
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] === arr[j]) {
arr.splice(j, 1);
j--;
}
}
}
9.数组交集,并集,差集
let a = [1,2,3]
let b = [4,3,2]
交集
(1).let intersect = new Set([...a].filter(v => b.has(v))); // [2,3]
(2).const jiaoji = (arr1, arr2) => {
return arr1.filter(v => arr2.some(j => v === j ));
}
jiaoji(a,b)
并集 let union = new Set([...a, ...b]) // [1,2,3,4]
差集
(1).difference = new Set([...a].filter(v => !b.has(v)); // [1, 4]
(2).const chaji = (arr1, arr2) => {
return arr1.filter(v => arr2.every(j => v !== j ));
}
chaji(a,b)
给定一个包括'(',')','{','}','[',']'的字符串
判断如果'()', '[]', '{}', '{{[]}}'为true, '(]', '[}'..为false
const isVolid = (v) => {
let items = [];
let len = v.length;
if (len % 2 !== 0) {
return false;
}
for (let i = 0; i < len; i++) {
let letter = items[items.length - 1];
switch (v[i]) {
case '(':
items.push('(');
break;
case '{':
items.push('{');
break;
case '[':
items.push('[');
break;
case ')':
if (letter === '(') {
items.pop()
}
break;
case '}':
if (letter === '{') {
items.pop()
}
break;
case ']':
if (letter === '[') {
items.pop()
}
break;
}
}
return items.length === 0;
}
- 斐波那契数列之和 (最后一项等于前面两项之和 0,1,1,2,3,5,8,13,21,34...)
const generateFib = (n) => {
let arr = [];
let i = 0;
while (i < n) {
if (i <= 1) {
arr.push(i);
} else {
arr.push(arr[i-1] + arr[i -2])
}
i++;
}
return arr
}
12.斐波那契第n项
const fibSuper = (n) => {
if (n < 2) return n;
const arr = [0, 1];
for (let i = 2; i <= n; i++) {
arr.push(arr[0] + arr[1]);
arr.splice(0, 1);
}
return arr[1]
}
13.求数组最大差值
const getMaxProfit = (arr) => {
let maxProfit = 0;
let minVal = arr[0];
for (let i = 0; i < arr.length; i++) {
const currentVal = arr[i];
minVal = Math.min(minVal, currentVal); // 取最小值
const temp = currentVal - minVal;
maxProfit = Math.max(maxProfit, temp);
}
return maxProfit;
}
14.求数组中每个数字出现的次数
// [2,5,5,9,9,17,22,28,30,30]
const keyWordCount = (arr) => {
return arr.reduce((pre, cur) => {
if (!pre[cur]) {
pre[cur] = 1
} else {
pre[cur]++
}
return pre;
}, {})
}
节流
// 一个函数执行后,只有大于规定时间才执行第二次,只让函数第一次执行生效,后面不生效
const throttle = function(fn, delay) {
let lastTime = 0;
return function() {
const nowTime = Date.now();
if (nowTime - lastTime > delay) {
fn.call(this);
}
lastTime = nowTime; // 同步时间
}
}
防抖
// 一个需要频繁触发的函数,在规定时间内,只让最后一次执行生效,前面不生效
const debounce = function (fn, delay) {
let timer = null;
return function() {
clearTimeout(timer);
timer = setTimeout(() => {
fn();
}, delay || 200)
}
}
深拷贝
function deepCopy(obj) {
if (typeof obj === 'object' && typeof obj !== 'function') {
return obj;
}
let o = Object.prototype.toString.call(obj) === '[object Array]' ? [] : {};
for (i in obj) {
if (obj.hasOwnProperty(i))
o[i] = typeof obj[i] === 'object' ? deepCopy(obj[i]) : obj[i];
}
return o;
}