对时间复杂度和空间复杂度的理解

时间复杂度

在算法中,所谓的时间复杂度可以简单的理解成为算法的运行时间。接下来我们可以简单的去看一下时间复杂度是怎么计算的

例子:
javascript 复制代码
function print1() {
  console.log('打印')
}
// 函数内代码只执行了1次

function print2(n) {
  for (let i = 0; i < n; i++) {
    console.log('打印')
  }
}

第一个 print1 很明显的看出来只执行了1次

第二个函数:对于print2 我们可以先假设 **n = 2

**

回到 n 这个数上,我们再计算一下执行了几次

可以得出结果就是 一共执行了 3n + 2次

结论

通常一段代码的总执行次数,我们会用T(n)来表示, 而如果n的数据比较大时,T(n)来表达就不是很合适。在算法中,我们通常会用T(n)的简化估算值 来计算代码的运行速度,而这个估算值就被称为时间复杂度。

T(n) --> 时间复杂度
  • print1 = T(n) = 1 --> 对于T(n)是个常数时,可以直接将其估算成 1 --> O(1)
  • print2 = T(n) = 3n + 2 --> 如果n足够大的时候,可以理解成忽略其常数和n前面的系数,也就n --> O(n)
  • 补充: T(n) = 4n^8 + 10n^7 + 2 -->同样的道理,n足够大时,取n的次方最大作为复杂度--> O(n^8)

常见的例子
例子1:
js 复制代码
function print1() {
  console.log('打印1') // 打印了一次
  console.log('打印2') // 打印了一次
  console.log('打印3') // 打印了一次
  console.log('打印4') // 打印了一次
  console.log('打印5') // 打印了一次
}
// 复杂度 O(1)
例子2:
js 复制代码
function print2(n) {
  for (let i = 0; i < n; i++) {
    console.log('打印') // 打印了一次
  }
}
// 复杂度 O(n)

可以简单总结出来:代码存在多少层循环,时间复杂度就是多少。

例子3:
js 复制代码
function print3(n) {
  for (let i = 0; i < n; i++) {
    for (let j = 0; j < n; j++) {
      console.log('打印') // 打印了一次
    }
  }
  for (let k = 0; k < n; k++) {
    console.log('打印') // 打印了一次
  }
}
// 当 i = 0,内部会执行 n + 1 次, i = 1, 持续 2n + 2,依次类推,应该会执行个 n*n + n = n^2+n 次。
// 复杂度为O(n^2)
例子4:
js 复制代码
function print4(n) {
  if (n > 100) {
    for (let i = 0; i < n; i++) {
      for (let j = 0; j < n; j++) {
        console.log('打印') // 打印了一次
      }
    }
  } else {
    for (let i = 0; i < n; i++) {
      console.log('打印') // 打印了一次
    }
  }
  
}
// 如果是存在判断条件,则还是以最长运行时间最为最终结果
// 复杂度为O(n^2)
例子5:
js 复制代码
function print5(n) {
  for (let i = 0; i < n; i++) {
    for (let j = i; j < n; j++) {
      console.log('打印') // 打印了一次
    }
  }
}
// i = 0 -> n
// i = 1 -> n - 1
// ...
// i = n - i -> 1
// T(n) = n + (n - 1) + (n - 2) + .... + 2 + 1 = n(n + 1) / 2 = 1/2 * n^2 + 1/2*n
// 复杂度为O(n^2)
例子6:
js 复制代码
function print6(n) {
  for (let i = 0; i < n; i * 2) {
    console.log('打印') // 打印了一次
  }
}
// 假设 n = 8
// T(n) = 3 --> 2^3 = 8 --> log(2)(8) = 3(指数和对数的转换)
// 复杂度可以简单表示成 O(logn) -->(当n足够大时,可以忽略其底数,只保留其真数和对数)

可以补充一下简单的数学知识

两者可以相互转换,转换公式为a^x=N <=> log(a)(N) = x

例子7:
js 复制代码
function print(n) {
  for(let j = 0; j < n; j++) {
    for (let i = 0; i < n; i * 2) {
      console.log('打印') // 打印了一次
    }
  }
}
// 由例子6可以简单得出:
// 复杂度为O(nlog(n))

空间复杂度

空间复杂度可以简单理解成一个算法在运行过程中占用存储空间大小 的度量。通常来说,计算一个算法的空间复杂度公式为:S(n) = O(fn(n)) 其中n 为问题的规模,fn为算法所占用空间大小的函数

例子:
js 复制代码
function print(n) {
  let a = []
  const b = 1 // 是个常量 -> 1
  for(let i = 0; i < n; i++) {
    a.push(i); // a的大小随的n变而变大
  }
}
// 我们可以简单的估量程序所占用 a占用了n个空间,b暂用了一个,一共为n+1 --> O(n)
常见的几种复杂度:
  • 如果申请的是有限个数(常量)的变量(变量空间 ),空间复杂度为 O(1)
  • 如果申请的是一维数组,队列或者链表(线性空间 )等,那么空间复杂度为 O(n)
  • 如果申请的是二维数组(二维空间 ),那么空间复杂度为 O(n²)
  • 如存在递归则比较特殊(递归空间 ),空间复杂度为O(n) (递归存在时,计算机会专门分配一块空间,来存储"方法调用栈",当进入更深一层函数时,会进行入栈操作,执行完会进行出栈操作, 因此递归所需要的内存空间跟递归的深度成正比。)
  • 如果是在循环体中申请的数组等,可能就需要取嵌套的乘积来作为空间复杂度,这种就需要具体的进一步分析。
相关推荐
chenziang120 分钟前
leetcode hot100 环形链表2
算法·leetcode·链表
Captain823Jack2 小时前
nlp新词发现——浅析 TF·IDF
人工智能·python·深度学习·神经网络·算法·自然语言处理
Captain823Jack2 小时前
w04_nlp大模型训练·中文分词
人工智能·python·深度学习·神经网络·算法·自然语言处理·中文分词
Aileen_0v03 小时前
【AI驱动的数据结构:包装类的艺术与科学】
linux·数据结构·人工智能·笔记·网络协议·tcp/ip·whisper
是小胡嘛3 小时前
数据结构之旅:红黑树如何驱动 Set 和 Map
数据结构·算法
m0_748255023 小时前
前端常用算法集合
前端·算法
呆呆的猫3 小时前
【LeetCode】227、基本计算器 II
算法·leetcode·职场和发展
Tisfy3 小时前
LeetCode 1705.吃苹果的最大数目:贪心(优先队列) - 清晰题解
算法·leetcode·优先队列·贪心·
余额不足121384 小时前
C语言基础十六:枚举、c语言中文件的读写操作
linux·c语言·算法
yuanManGan5 小时前
数据结构漫游记:静态链表的实现(CPP)
数据结构·链表