文章目录
-
- [1. 大O表示法(Big O Notation)](#1. 大O表示法(Big O Notation))
- [2. 时间复杂度计算步骤](#2. 时间复杂度计算步骤)
-
- [2.1 常见复杂度等级(从快到慢)](#2.1 常见复杂度等级(从快到慢))
- [3. 时间复杂度具体示例(Java)](#3. 时间复杂度具体示例(Java))
-
- [例1:常数阶 O(1)](#例1:常数阶 O(1))
- [例2:线性阶 O(n)](#例2:线性阶 O(n))
- [例3:平方阶 O(n²)](#例3:平方阶 O(n²))
- [例4:对数阶 O(log n)](#例4:对数阶 O(log n))
- [例5:递归(斐波那契) O(2ⁿ)](#例5:递归(斐波那契) O(2ⁿ))
- [4. 空间复杂度计算](#4. 空间复杂度计算)
-
- [示例1:O(1) 空间](#示例1:O(1) 空间)
- [示例2:O(n) 空间](#示例2:O(n) 空间)
- [示例3:递归栈空间 O(n)](#示例3:递归栈空间 O(n))
- [5. 练习建议](#5. 练习建议)
1. 大O表示法(Big O Notation)
大O表示法描述算法性能的上界,忽略低阶项和常数系数,只保留增长最快的部分。
- 一个循环执行
n次 → O(n) - 双重循环各执行
n次 → O(n²) - 常数个操作 → O(1)
2. 时间复杂度计算步骤
- 找出基本操作(循环、递归、数组访问等最内层的操作)。
- 用
n表示基本操作的执行次数。 - 使用大O表示:保留最高次项,去除系数和常数。
2.1 常见复杂度等级(从快到慢)
| 表示法 | 名称 | 典型场景(Java代码示意) |
|---|---|---|
| O(1) | 常数阶 | 数组取值、简单算术 |
| O(log n) | 对数阶 | 二分查找 |
| O(n) | 线性阶 | 单层循环 |
| O(n log n) | 线性对数阶 | 归并排序、堆排序 |
| O(n²) | 平方阶 | 双层循环(冒泡排序) |
| O(2ⁿ) | 指数阶 | 无剪枝递归(斐波那契) |
| O(n!) | 阶乘阶 | 全排列的暴力解法 |
3. 时间复杂度具体示例(Java)
例1:常数阶 O(1)
java
public int sumFirstTwo(int[] arr) {
return arr[0] + arr[1]; // 只执行固定次数的加法,与数组长度n无关
}
分析 :无论数组多大,都只执行几次操作 → O(1)。
例2:线性阶 O(n)
java
public int findMax(int[] arr) {
int maxVal = arr[0];
for (int num : arr) { // 循环 n 次
if (num > maxVal) {
maxVal = num;
}
}
return maxVal;
}
分析 :循环次数 = n → O(n)。
例3:平方阶 O(n²)
java
public void bubbleSort(int[] arr) {
int n = arr.length;
for (int i = 0; i < n; i++) { // 外层 n 次
for (int j = 0; j < n - i - 1; j++) { // 内层约 n/2 次
if (arr[j] > arr[j + 1]) {
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
分析 :比较次数 ≈ n*(n-1)/2 → 最高次项 n² → O(n²)。
例4:对数阶 O(log n)
java
public int binarySearch(int[] arr, int target) {
int left = 0, right = arr.length - 1;
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;
}
}
return -1;
}
分析 :每次循环将查找区间减半,最坏需要 log₂(n) 次 → O(log n)。
例5:递归(斐波那契) O(2ⁿ)
java
public int fib(int n) {
if (n <= 1) {
return n;
}
return fib(n - 1) + fib(n - 2);
}
分析 :画出递归树,每个节点分出两个子节点,调用总数 ≈ 2ⁿ → O(2ⁿ)(极差)。
优化 :使用记忆化(动态规划)可降到 O(n)。
4. 空间复杂度计算
空间复杂度衡量算法额外占用的内存(输入数据本身不计入)。同样用大O表示。
常见情况:
- O(1) :只用了固定数量的变量(如几个
int、指针)。 - O(n) :需要大小为
n的数组、HashMap、递归栈等。 - O(n²) :需要
n×n的二维数组。
示例1:O(1) 空间
java
public void reverseArray(int[] arr) {
int left = 0, right = arr.length - 1;
while (left < right) {
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
left++;
right--;
}
// 只用了 left, right, temp 三个变量,不随 n 增长
}
示例2:O(n) 空间
java
public int[] copyArray(int[] arr) {
int[] newArr = new int[arr.length]; // 额外分配 n 个元素的数组
for (int i = 0; i < arr.length; i++) {
newArr[i] = arr[i];
}
return newArr;
}
示例3:递归栈空间 O(n)
java
public int factorial(int n) {
if (n == 0) {
return 1;
}
return n * factorial(n - 1);
}
分析 :递归深度为 n,系统栈需要保存 n 个调用帧 → 空间复杂度 O(n)。(迭代版本可做到 O(1))
5. 练习建议
- 刷题时 主动分析 自己代码的复杂度,并对照官方题解。
- 多写 Java 内置数据结构 的操作:
ArrayList.get/set→ O(1);LinkedList.get→ O(n);HashMap平均 O(1) 等。 - 理解不同算法在 Java 中的实现差异,例如递归 vs 迭代对空间复杂度的影响。
希望这篇博客对你有所帮助,也欢迎大家在评论区交流讨论!如果觉得有用,不妨点个赞支持一下 !感谢,共勉,祝好!😊