让我详细解释如何分析这段代码的时间复杂度:
🔍 代码逐行分析
@Test
public void test2(int n) {
int sum = 1; // 1. 初始化操作,时间复杂度: O(1)
while (sum < n) { // 2. 循环条件判断
sum *= 2; // 3. 循环体内的操作,时间复杂度: O(1)
}
System.out.println(sum); // 4. 输出操作,时间复杂度: O(1)
}
📊 时间复杂度计算过程
循环执行次数分析
让我们追踪循环的执行过程:
| 循环次数 | sum的值 | 数学表达式 |
|---|---|---|
| 0 | 1 | 2⁰ = 1 |
| 1 | 2 | 2¹ = 2 |
| 2 | 4 | 2² = 4 |
| 3 | 8 | 2³ = 8 |
| 4 | 16 | 2⁴ = 16 |
| ... | ... | ... |
| k | 2ᵏ | 2ᵏ |
数学推导
循环会在满足以下条件时停止:
text
2ᵏ ≥ n
对两边取对数:
text
k ≥ log₂n
因此,循环次数为:⌈log₂n⌉(向上取整)
🎯 时间复杂度结论
总时间复杂度:O(log n)
-
最好情况:O(1) - 当 n ≤ 1 时,循环不执行
-
最坏情况:O(log n) - 当 n 很大时
-
平均情况:O(log n)
📈 可视化理解
text
n值 循环次数 时间复杂度 n=1 0 O(1) n=2 1 O(1) n=4 2 O(2) n=8 3 O(3) n=16 4 O(4) n=32 5 O(5) n=1024 10 O(10) n=1048576 20 O(20)
可以看到,当n增长100万倍时,循环次数只从10增加到20!
🔢 与其他复杂度的对比
// O(1) - 常数时间
int sum = n * (n + 1) / 2;
// O(log n) - 对数时间(你的代码)
while (sum < n) {
sum *= 2;
}
// O(n) - 线性时间
for (int i = 0; i < n; i++) {
// 操作
}
// O(n²) - 平方时间
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
// 操作
}
}
🧠 判断时间复杂度的技巧
-
识别循环结构
-
分析循环变量的变化方式
-
每次加固定值:O(n)
-
每次乘固定值:O(log n)
-
每次指数增长:O(log log n)
-
-
计算循环次数
-
忽略常数项和低阶项
📝 练习:判断其他类似代码
// 例1:时间复杂度是多少?
int i = 1;
while (i < n) {
i *= 3; // O(log₃n) = O(log n)
}
// 例2:时间复杂度是多少?
int j = n;
while (j > 1) {
j /= 2; // O(log n)
}
// 例3:时间复杂度是多少?
int k = 1;
while (k < n) {
k += 5; // O(n) - 线性时间
}
✅ 总结
你的代码 test2(int n) 的:
-
时间复杂度:O(log n)
-
空间复杂度:O(1) - 只使用了固定数量的变量
-
效率等级:高效算法(对数时间复杂度很好)
这是因为循环变量 sum 以指数速度增长(每次乘以2),所以只需要很少的循环次数就能达到目标值n。

785

被折叠的 条评论
为什么被折叠?



