注意:时间复杂度的核心是关注算法在输入规模增长时的增长速率。我们通过分析代码的嵌套层级和每一层循环的执行情况,来推断出复杂度的增长趋势。我们需要通过逻辑推导出时间复杂度的增长速率,而不纠结于具体的执行次数。
例子 1: 三层嵌套循环
function example1(n) {
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
for (let k = 0; k < n; k++) {
// 假设这里的操作是 O(1)
console.log(i, j, k);
}
}
}
}
时间复杂度计算:
- 最外层循环:
i从 0 到 n,共执行 n 次。 - 第二层循环:对于1个i值,
j从 0 到 n,也执行 n 次。 - 第三层循环:对于1个j值,
k从 0 到 n,也执行 n 次。
内层语句执行次数:nXnXn=n³
总时间复杂度:O(n³)
例子 2: 外层循环依赖于内层循环
function example2(n) {
for (let i = 0; i < n; i++) {
for (let j = 0; j < i; j++) {
for (let k = 0; k < j; k++) {
// 假设这里的操作是 O(1)
console.log(i, j, k);
}
}
}
}
时间复杂度计算:
- 最外层循环:
i从 0 到 n,共执行 n 次。 - 第二层循环:对于1个i值,
j从 0 到 i,执行次数为 i 次。j和i是线性关系。简化为 O(n)。 - 第三层循环:对于1个j值,
k从 0 到 j,执行次数为 j 次。k和j是线性关系。简化为 O(n)。
总时间复杂度:O(n³)
例子 3: 每层循环的次数不同
function example3(n) {
for (let i = 0; i < n; i++) {
for (let j = 0; j < n / 2; j++) {
for (let k = 0; k < n / 3; k++) {
// 假设这里的操作是 O(1)
console.log(i, j, k);
}
}
}
}
时间复杂度计算:
- 最外层循环:
i从 0 到 n,执行 n 次。 - 第二层循环:对于1个i值,
j从 0 到n / 2,执行 n / 2 次。可以简化为 O(n)。 - 第三层循环:对于1个j值,
k从 0 到n / 3,执行 n / 3 次。可以简化为 O(n)。
去除常数项,总的时间复杂度简化为 O(n³)。
总时间复杂度:O(n³)
例子 4: 内层循环的次数逐渐减少
function example4(n) {
for (let i = 0; i < n; i++) {
for (let j = 0; j < n - i; j++) {
for (let k = 0; k < j; k++) {
// 假设这里的操作是 O(1)
console.log(i, j, k);
}
}
}
}
时间复杂度计算:
- 最外层循环:
i从 0 到 n,共执行 n 次。 - 第二层循环:对于1个i值,
j从 0 到n - i,j和i是线性关系。简化为 O(n)。 - 第三层循环:对于1个j值,
k从 0 到 j,k和j是线性关系。简化为 O(n)。
总时间复杂度:O(n³)
例子 5: 带有对数的嵌套循环
function example5(n) {
for (let i = 0; i < n; i++) {
for (let j = 1; j < n; j *= 2) { // j 值以2的倍数递增
for (let k = 0; k < n; k++) {
// 假设这里的操作是 O(1)
console.log(i, j, k);
}
}
}
}
时间复杂度计算:
- 最外层循环:
i从 0 到 n,执行 n 次。 - 第二层循环:对于1个i,
j指数增长,因此这个循环执行了 O(log n) 次。 - 第三层循环:对于1个j,
k从 0 到 n,执行 n 次。
总的时间复杂度为:nXlog nXn=n² log n
总时间复杂度:O(n² log n)