JS中的时间复杂度和空间复杂度

218 阅读2分钟

JS中的时间复杂度和空间复杂度

学习算法的基础就是明白时间和空间复杂度的计算,这样才能知道还有什么优化的地方。

时间复杂度

一些常见的时间复杂度及其排序(从快到慢):

  • O(1)O(1) - 常数时间
  • O(logn)O(log n) - 对数时间
  • O(n)O(n) - 线性时间
  • O(nlogn)O(n log n) - 线性对数时间
  • O(n2)O(n^2) - 平方时间
  • O(2n)O(2^n) - 指数时间
  • O(n!)O(n!) - 阶乘时间

O(1)O(1)

算法的消耗不会随着变量的增长而增长,无论代码多少行时间复杂度都是O(1)O(1)

let n = 1
let n2= 2
// ...

O(logn)O(log n)

通常出现在分治法或二分查找等场景中,每步操作将问题规模按照倍数减少。

function binarySearch(arr, target) {
    let left = 0;
    let right = arr.length - 1;

    while (left <= right) {
        let mid = Math.floor((left + right) / 2);
        if (arr[mid] === target) return mid;
        else if (arr[mid] < target) left = mid + 1;
        else right = mid - 1;
    }

    return -1; // 未找到目标值
}

O(n)O(n)

操作时间与输入数据的大小成正比。

let sum = 0;
for (let i = 0; i < arr.length; i++) {
    sum += arr[i];
}

O(nlogn)O(n log n)

通常出现在高效排序算法中,如快速排序、归并排序。

function mergeSort(arr) {
    if (arr.length <= 1) return arr;

    const mid = Math.floor(arr.length / 2);
    const left = mergeSort(arr.slice(0, mid));
    const right = mergeSort(arr.slice(mid));

    return merge(left, right);
}

function merge(left, right) {
    let result = [], l = 0, r = 0;

    while (l < left.length && r < right.length) {
        if (left[l] < right[r]) result.push(left[l++]);
        else result.push(right[r++]);
    }

    return result.concat(left.slice(l)).concat(right.slice(r));
}

O(n2)O(n^2)

操作时间与输入数据大小的平方成正比,常见于简单的嵌套循环。

function fn() {
    for (let i = 0; i < n; i++) {
        for (let j = 0; j < n; j++) {
        };
    };
};

O(2n)O(2^n)

操作时间随着输入数据大小呈指数增长,常见于递归解决方案中。

function fn(n) {
    if {n <= 2}{
        return 1
    }
    return fun(n - 1) + fun(n - 2)
};

O(n!)O(n!)

操作时间随着输入数据大小的阶乘增长,通常出现在全排列生成等问题中。

let results = [];

function backtrack(path, options) {
    if (options.length === 0) {
        results.push(path);
        return;
    }

    for (let i = 0; i < options.length; i++) {
        let newPath = path.concat(options[i]);
        let newOptions = options.slice(0, i).concat(options.slice(i + 1));
        backtrack(newPath, newOptions);
    }
}

backtrack([], arr);

空间复杂度

O(1)O(1)

const n = 1;

O(n)O(n)

  1. 一维数组
const arr = []
  1. 链表
class ListNode {
    constructor(value) {
        this.value = value;
        this.next = null;
    }
}
const head = new ListNode(0);
  1. 哈希表(Object、Map、WeakMap、Set、WeakSet)
const obj = {}
const map = new Map()
const weakMap = new WeakMap()
const set = Set()
const weakSet = new WeakSet()
  1. 字符串
const str = ''
  1. 递归调用栈 一些递归算法,如果最大递归深度为 (n),那么其调用栈的空间复杂度也是 (O(n))。例如,计算斐波那契数列的简单递归实现:
function fibonacci(n) {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
}

O(n2)O(n^2)

  1. 二维数组
let matrix = [];
for (let i = 0; i < n; i++) {
    matrix[i] = new Array(n).fill(0);
}