一、基本概念
1、时间复杂度

1、O(1)
一次就够
function fn(obj={}){return obj.a + obj.b + obj.c //4~5}
2、O(n)
和传输的数据量一样
function fn(arr=[]){for(let i=0;i<arr.length;i++){console.log(arr[i])}}
3、O(n^2)
数据量的平方
function fn(arr=[]){for(let i=0; i<arr.length; i++){for(let j=0; j<arr.length; j++){console.log(arr[j])}}}
4、O(logn)
数据量的对数
function fn(arr){//二分查找、有序数组}
5、O(nlogn)
数据量 * 数据量的对数
function fn(arr=[]){for(let i=0;i<arr.length;i++){//二分}}
2、空间复杂度
1、O(1)
一次就够
function fn(){const arr1 = []const arr2 = []}
2、O(n)
和传输的数据量一样
function fn(arr=[]){const arr2 = []for(let i=0; i<arr.length; i++){arr2[i] = arr[i] + 10}return arr2}
3、O(n^2)
数据量的平方
4、O(logn)
数据量的对数
5、O(nlogn)
数据量 * 数据量的对数
3、js操作的时间复杂度
前端重时间,轻空间
(1)高时间复杂度
unshift shift splice
数组是一个有序结构,unshift 操作非常慢!!! O(n)
(2)低时间复杂度
pop push slice 原数组没被改变
4、二叉查找树
每一个节点都可能有任意个数的子节点(在二叉树中我们称之为度,2 个子节点就是 2 度)
当某个节点拥有 0 个子节点时,我们称之为叶子节点或终端节点。
每一个节点的左子节点的数值要小于当前节点,每一个节点的右子节点要大于当前节点
5、平衡二叉树
二、算法题
1、将一个数组旋转k步
思路1:
将 k 后面的元素,挨个 pop 然后 unshift 到数组前面
复杂度:
时间复杂度:O(n^2)
空间复杂度:O(1)
function rotate1(arr: number[], k: number): number[] {const length = arr.lengthif (!k || length === 0) return arrconst step = Math.abs(k % length) // abs 取绝对值// O(n^2)for (let i = 0; i < step; i++) {const n = arr.pop()if (n != null) {arr.unshift(n) // 数组是一个有序结构,unshift 操作非常慢!!! O(n)}}return arr}
思路2:
- 将
k后面的所有元素拿出来作为part1 - 将
k前面的所有元素拿出来作为part2 - 返回
part1.concat(part2)
复杂度:
时间复杂度:O(1)
空间复杂度:O(n)
function rotate2(arr: number[], k: number): number[] {const length = arr.lengthif (!k || length === 0) return arrconst step = Math.abs(k % length) // abs 取绝对值// O(1)const part1 = arr.slice(-step) // O(1)const part2 = arr.slice(0, length - step)const part3 = part1.concat(part2)return part3}
测试用例
npx jest ./src/01-algorithm/array-rotate.test.ts
/*** @description Array rotate test* @author cq*/import { rotate1, rotate2 } from './array-rotate'describe('数组旋转', () => {it('正常情况', () => {const arr = [1, 2, 3, 4, 5, 6, 7]const k = 3const res = rotate2(arr, k)expect(res).toEqual([5, 6, 7, 1, 2, 3, 4]) // 断言})it('数组为空', () => {const res = rotate2([], 3)expect(res).toEqual([]) // 断言})it('k 是负值', () => {const arr = [1, 2, 3, 4, 5, 6, 7]const k = -3const res = rotate2(arr, k)expect(res).toEqual([5, 6, 7, 1, 2, 3, 4]) // 断言})it('k 是 0', () => {const arr = [1, 2, 3, 4, 5, 6, 7]const k = 0const res = rotate2(arr, k)expect(res).toEqual(arr) // 断言})it('k 不是数字', () => {const arr = [1, 2, 3, 4, 5, 6, 7]const k = 'abc'// @ts-ignoreconst res = rotate2(arr, k)expect(res).toEqual(arr) // 断言})})
性能测试
const arr1 = []for (let i = 0; i < 10 * 10000; i++) {arr1.push(i)}console.time('rotate1')rotate1(arr1, 9 * 10000)console.timeEnd('rotate1') // 885ms O(n^2)const arr2 = []for (let i = 0; i < 10 * 10000; i++) {arr2.push(i)}console.time('rotate2')rotate2(arr2, 9 * 10000)console.timeEnd('rotate2') // 1ms O(1)
思路1 pop unshift
思路2 拆分两个数组,concat连接

