左哥算法 - 如何判断算法复杂度

159 阅读2分钟

根据左哥的思路,通俗易懂地理解算法复杂度。

1. 时间复杂度基础概念

把算法比作做饭:

O(1):相当于拿出一个速食面,直接泡
O(n):相当于炒一盘菜,食材越多,时间越长
O(n²):相当于给n个人每人炒n个菜
O(logn):相当于每次处理时食材减半(比如切西瓜)

2. 常见时间复杂度排序(从快到慢)

O(1) < O(logn) < O(n) < O(nlogn) < O(n²) < O(2ⁿ)

具体例子:
数组长度n=100时:
O(1)     = 1次操作
O(logn)  ≈ 7次操作    (2⁷ ≈ 100)
O(n)     = 100次操作
O(nlogn) ≈ 700次操作
O(n²)    = 10000次操作
O(2ⁿ)    = 天文数字

3. 如何计算时间复杂度

基本法则:

  1. 只看最高项
for(int i = 0; i < n; i++) {
    System.out.println(i);  // 执行n次
}
System.out.println("完成");  // 执行1次

// O(n + 1) => O(n)
  1. 忽略系数
for(int i = 0; i < 2n; i++) {  // 执行2n次
    System.out.println(i);
}

// O(2n) => O(n)
  1. 嵌套循环相乘
for(int i = 0; i < n; i++) {
    for(int j = 0; j < n; j++) {
        System.out.println(i + j);
    }
}

// O(n * n) = O(n²)

4. 常见代码的复杂度分析

O(1) 常数时间

int a = 1;
int b = 2;
int c = a + b;

O(n) 线性时间

// 遍历一次数组
for(int i = 0; i < n; i++) {
    System.out.println(arr[i]);
}

O(logn) 对数时间

// 二分查找
while(left <= right) {
    int mid = left + (right - left) / 2;
    if(arr[mid] == target) return mid;
    else if(arr[mid] < target) left = mid + 1;
    else right = mid - 1;
}

O(nlogn) 线性对数时间

// 归并排序
public void mergeSort(int[] arr) {
    // 每次分成两半 O(logn)
    // 每层都要处理n个数 O(n)
    // 总复杂度 O(nlogn)
}

5. 实际案例分析

例1:找数组最大值

int findMax(int[] arr) {
    int max = arr[0];
    for(int i = 1; i < arr.length; i++) {
        if(arr[i] > max) max = arr[i];
    }
    return max;
}
// 复杂度:O(n)

例2:冒泡排序

void bubbleSort(int[] arr) {
    for(int i = 0; i < arr.length - 1; i++) {
        for(int j = 0; j < arr.length - 1 - i; j++) {
            if(arr[j] > arr[j+1]) {
                // 交换
            }
        }
    }
}
// 复杂度:O(n²)

6. 空间复杂度

空间复杂度看额外使用的空间:

// O(1) 空间
int sum(int[] arr) {
    int result = 0;  // 只用了一个变量
    for(int num : arr) {
        result += num;
    }
    return result;
}

// O(n) 空间
int[] copyArray(int[] arr) {
    int[] newArr = new int[arr.length];  // 创建了一个新数组
    for(int i = 0; i < arr.length; i++) {
        newArr[i] = arr[i];
    }
    return newArr;
}

7. 实用技巧

  1. 看循环次数

    • 一层循环:一般是O(n)
    • 两层循环:一般是O(n²)
    • 每次规模减半:一般是O(logn)
  2. 常见算法复杂度

    • 二分查找:O(logn)
    • 快速排序:O(nlogn)
    • 冒泡排序:O(n²)
    • 哈希表查找:O(1)