前端面试(一):算法复杂度分析

前言

啊~~~痛苦的暑期实习面试开始了。

笔者在面试写算法题时就经常被面试官问到:"这个方法的时间复杂度是多少?空间复杂度是多少?"

但笔者只对算法复杂度略知一二,回答的时候都犹犹豫豫不敢确定:"emm,是O(n)吗?"

所以为了避免以上情景再次发生,笔者决定要好好整理一下算法复杂度分析,并以此作为我暑期实习和秋招复习第一个专题,给自己打气也分享给一起找工作的朋友们!

算法复杂度

为什么需要算法复杂度

首先,有时候用算法解决问题时,我们不单单需要考虑问题能否解决,还需要考虑解决问题的性能开销,比如要花多长时间,要消耗多少空间。算法的性能开销需要一个衡量标准,所以我们很需要算法复杂度

其次,算法复杂度会不会计算也是衡量程序员的一个重要标准,算法复杂度的计算可以帮助程序员更好地理解算法的运行,优化程序的性能,并因地制宜地选择算法。

算法复杂度分析的是什么

算法复杂度主要用来分析算法的时间开销和空间开销,我们需要了解时间复杂度空间复杂度

  • 时间复杂度:衡量运行算法完需要的时间。
  • 空间复杂度:衡量运行算法需要的空间。

大O计法

大O计法常常用来描述算法复杂度,它既可以用来描述时间复杂度也可以描述空间复杂度。

以时间复杂度 T(n) = O(f(n)) 为例子,这里 T(n) 表示算法执行的总时间,n 表示数据的规模,f(n) 表示每行代码的执行总次数,O 表示执行时间与 f(n) 的表达式成正比。

O的具体讲解可以看这里啦:# 一文搞懂算法复杂度分析:大O符号你都搞不懂,所以只能搬砖到秃顶?

时间复杂度

算法时间复杂度是通过计算算法所需要运行的时间实现的,算法的时间复杂度计作:T(n) = O(f(n)) , n 为数据的规模,f(n) 表示每行代码的执行总次数,O 表示执行时间与 f(n) 的表达式成正比。

用大O计法来表示的时间复杂度并不代表算法真正运行的时间,而是表示代码运行时间会随数据规模的变化而变化,大O计法也称为渐进时间复杂度。

PS: 笔者感觉用大O计法的时候,只需要关注关键细节,比如循环啊,对于常数次的运算可以忽略哈。

常见的时间复杂度

O(1) 常数级

在下面的代码中,T(n) = O(1),a和b无论怎么变,代码的执行次数还是这么多,运算时间也很稳定。

对于常数级的时间复杂度来说,代码的执行时间不会随着数据规模的增加而增加。

js 复制代码
const sum = (a, b) => {
  return a + b; // t
}

O(n) 线性阶

在下面的这段代码中,T(n) = O(2n+1), 当数据规模n无限增大的时候,低阶、常量都可以忽略不计,T(n) 可以简化表示为 O(n),代码的执行时间会随着数据规模的增加而增加。

js 复制代码
const sum = (n) => {
 let count = 0 ; //t 一个时间单位
 for(let i = 0; i < n; i++){ // t*n
   count = count + i; // t*n  
 }
 return count;
}  

O(m+n) 线性阶

在下面的这段代码中,T(n) = O(m+n), 因为算法运行的时间与两个变量 m、n 相关。

js 复制代码
const sum = (m, n) => {
 let sum1 = 0 ; //t 一个时间单位
 for(let i = 0; i < m; i++){ // t*m
   sum1 = sum1 + i; // t*m
 }

 let sum2 = 0 ; //t 一个时间单位
 for(let i = 0; i < n; i++){ // t*n
   sum2 = sum2 + i; // t*n  
 }
 
 return sum1 + sum2;
}  

O(m*n)

在下面的这段代码中,我们可以看到循环中的关键代码要运行mn次,故 T(n) = O(mn)。

比较特殊的情况是,当 m = n 时, T(n) = O(n*n),代码执行时间随着数据规模的增加而平方增长。

js 复制代码
const sum = (m, n) => {
 let count = 0 ; //t 一个时间单位
 for(let i = 0; i < m; i++){ // t*m
   for(let j = 0; j < n; j++){ // t*m*n
     count = count + i*j; // t*m*n 
   }
 }
 return count;
}  

O(n*n)

在下方的这段代码中,代码执行时间随着数据规模n的增加而平方增长,时间复杂度 T(n) = O(n*n)。

js 复制代码
const sum = (n) => {
 let count = 0 ; //t 一个时间单位
 for(let i = 0; i < n; i++){ // t*n
   for(let j = 0; j < n; j++){ // t*n*n
     count = count + i*j; // t*n*n 
   }
 }
 return count;
}  

O(logn) 对数阶

在下方的这段代码中,代码执行时间随着数据规模n的增加而对数增长,所以时间复杂度 T(n) = O(logn)

js 复制代码
const sum = (n) => {
  let count = 0;
  let i = 1;
  while (i < n) {
    i=i*2;
    count = count + i;
  }
  return count;
}

参考文档中的 O(logn) 推导过程:

在代码中,while循环中每次将i乘以2,直到i大于n,结束此循环。

当循环x次后,i>n,循环结束,也就是2的x次方等于n,即x=log2n,也就是说循环log2n次以后,循环就结束了。代码的时间复杂度为O(logn)。

找出while循环中的结束条件,判断时间复杂度。

带有while循环的代码,大概率是对数时间复杂度为O(logn)

时间复杂度比较

各个算法时间复杂度的大小比较大约是酱紫的:

O(1) <<< O(logn) <<< O(n) <<< O(nlogn) <<< O( <math xmlns="http://www.w3.org/1998/Math/MathML"> n 2 n^2 </math>n2) <<< O( <math xmlns="http://www.w3.org/1998/Math/MathML"> n 3 n^3 </math>n3) <<< O( <math xmlns="http://www.w3.org/1998/Math/MathML"> 2 n 2^n </math>2n)<<< O(n!)

空间复杂度

算法空间复杂度是通过计算算法所需要存储空间实现的,算法的空间复杂度计作:S(n) = O(f(n)) , n 为数据的规模,f(n) 表示 n 所占的存储空间的函数,O 表示存储空间与 f(n) 的表达式成正比。

用大O计法来表示的空间复杂度并不代表算法真正占用的存储空间,而是表示算法占用的存储空间与数据规模的增长关系,大O计法也称为渐进空间复杂度。

常见的空间复杂度

O(1) 常数级

在下面的代码中,算法只占用了容量为1的数组,S(n) = O(1)。

js 复制代码
const array = () => {
  let arr = new Array(1).fill(0);
  return arr;
}

O(n) 线性阶

在下面的这段代码中,算法开辟了容量为n的数组,算法占用的存储空间会随着数据规模n的增加而增加,所以S(n) = O(n)。

js 复制代码
const array = () => {
  let arr = new Array(n).fill(0);
  return arr;
}

O(n*n)

在下面的这段代码中,算法创建了一个nn的二维数组,算法占用的存储空间会随着数据规模n的增加而平方增加S(n) = O(nn)。

js 复制代码
const matrix = (n) => {
 let m = new Array(n).fill(0).map(item => new Array(n).fill(0));
 return m;
}  

空间复杂度比较

一般我们会用到的空间复杂度有 O(1), O(n), O( <math xmlns="http://www.w3.org/1998/Math/MathML"> n 2 n^2 </math>n2), 它们占用的空间大小关系为:

O(1) <<< O(n)<<< O( <math xmlns="http://www.w3.org/1998/Math/MathML"> n 2 n^2 </math>n2)

参考文档

  1. 算法复杂度怎么计算
  2. 干货|算法复杂度分析看这一篇就够了
  3. 数据结构《二》算法时间复杂度 --- 大O记法
  4. 一文讲透算法中的时间复杂度和空间复杂度计算方式
  5. 一文搞懂算法复杂度
相关推荐
SRY122404192 小时前
javaSE面试题
java·开发语言·面试
不二人生5 小时前
SQL面试题——连续出现次数
hive·sql·面试
清酒伴风(面试准备中......)6 小时前
Java集合 List——针对实习面试
java·面试·list·实习
CXDNW9 小时前
【网络面试篇】其他面试题——Cookie、Session、DNS、CDN、SSL/TLS、加密概念
网络·笔记·面试·cdn·dns·cookie
正小安13 小时前
HTTP 和 HTTPS 的区别 - 2024最新版前端秋招面试短期突击面试题【100道】
前端·http·面试·https
航火火13 小时前
回首遥望-C++内存对齐的思考
c++·面试·架构
寻求出路的程序媛13 小时前
面试:TCP、UDP如何解决丢包问题
tcp/ip·面试·udp
程序猿进阶17 小时前
为什么数学常数在 powershell 中以不同的方式截断?
java·linux·服务器·前端·后端·面试·powershell
百晓生说测试17 小时前
外包干了5年,技术退步太明显了。。。。。
自动化测试·软件测试·功能测试·程序人生·面试·职场和发展
独行soc19 小时前
#渗透测试#SRC漏洞挖掘#CSRF漏洞的防御
前端·安全·web安全·面试·csrf