算法的复杂度估算在所有的算法面试中,有一个问题几乎是逃不掉的—你的算法时间复杂度是多少?在一般的企业面试中,算法复杂

在计算复杂度时,我们通常会用O(n)/O(nlogn)来表示。那么究竟什么是大O呢?

其中a、b、c、d表示常数,是固定不变的。换句话说,随着数据规模n的不断增大,算法效率的改变和a、b、c、d常数的关系是不大的。而和logn、n、nlogn、n^2关系巨大,所以我们通常省略常数项。

比如下面这个例子,算法AO(n)所需执行指令数是10000*n,而算法BO(n^2)所需执行指令数是10*n^2。

而且通过这张图我们可以很好的理解,随着输入数据量的增大,他们的增长速度是完全不同的。

相信现在大家对O(n)已经有了初步的认识,那么我们来看O(n)更严格的定义。在学术界,严格来讲,O(f(n))表示算法执行的上界。什么叫「算法执行的上界」呢?

而在实际情况中,也存在这种情况的复杂度:O(AlogA+B),而A和B是没有关系的。这个时候,我们就不能合并算法复杂度。

你可能会想,这个问题还不简单

1、每一个字符串按照字母序排序:每一次排序都是nlogn,一共有n个字符串,所以是n*nlogn2、之后再将整个字符串数组按照字典序排序nlogn

把他们相加起来,O(n*nlogn+nlogn)=O(n^2logn)

很遗憾,这个想法是错的。

首先,「这个字符串」的长度和「整个字符串数组」混在了一起,他们是没有关系的。所以,我们需要将这两个参数拆开。假设最长的字符串长度为s;数组中有n个字符串。对每个字符串排序:O(slogs)。将数组中的每一个字符串按照字母序排序:O(n*slog(s))

快速排序算法,最差的情况是O(n^2),最好的情况是O(nlogn)。但我们把排序算法的复杂度约定为O(nlogn),因为对于平均情况来说,他的复杂度就在这个。

为了让大家对对数据规模有一个概念,在这里我们用程序来说明。运行一个O(n)的程序,n的取值从1、10……10^9。

如果你想要在1s之内解决问题:

O(n^2)的算法可以处理大约10^4级别的数据,O(n)的算法可以处理大约10^8级别的数据,O(nlogn)的算法可以处理大约10^7级别的数据,因为lg10^7约等于7。

那么在面试中,我们就可以根据数据规模大致估算算法的复杂度。如果面试管说,我的数据规模是10^8级别。那就可以确定,算法复杂度基本是O(n)。(当然有的时候O(nlogn)也是可以的,这是因为logn是复杂度非常低的一个级别,处理速度也是非常快的。)

如果面试官提示说,我们这个算法只需要处理10^3的数据。这个时候给我们留下了足够的空间,设计一个O(n^2)的复杂度就可以满足要求。

constsum=(n)=>{if(n===0){return0;}returnn+sum(n-1)}空间复杂度:O(n)递归调用的深度是n,我们的系统栈中需要压入n个状态。换句话说,在整个递归调用中,递归的深度是多少,我们的空间复杂度就是多少。

functionswapTwoNumbers(a,b){lettemp=a;a=b;b=temp;}在这个算法中没有数据规模的变化,也就是常数级别的算法,所以算法复杂度是O(1)

严格地讲,这个算法执行的指令数和数据复杂度是成n^2比例关系的。

来看看minIndex=j执行了多少次。

比如大家都很熟悉的二分查找法:

//把number转换为string的操作:functionnumberToString(num){lets=""while(num){s+='0'+num%10;num/=10;}reverse(s)returns;}仔细看这个算法,它的复杂度相当于:n经过几次“除以10”操作后,等于0?经过上面的学习,我们很快可以得到答案log(10)n=O(logn)

上面我们说过,看到双重循环,基本可以断定为O(n^2)级别的算法。但是也有特例,比如下面这个:

无论是归并排序还是快速排序,都用到了递归算法。

由于这两个算法复杂度都是O(nlogn)级别的,刚接触算法的时候,你可能会认为递归算法的复杂度就是O(nlogn)。

当然这个结论是不对的,一定要具体问题具体分析。

第一种情况很简单,我们只会进行一次递归调用。

最典型的例子就是二分查找:

再比如:计算0-n的和

此时我们应该关系计算调用的次数。

functionf(n){if(n===0){return0}returnf(n-1)+f(n-1)}通常,我们可以画一颗递归树,比如f(3)时:

所以,我们要想知道f(3)调用了多少次,只需要数树上的节点就可以了。

1+2+4+8=15

2^0+2^1+2^2+2^3+……+2^n=2^(n+1)-1

复杂度O(2^n)

这其实是一个等比数列的求和公式。经过计算之后,它的结果是2的N次方级别的数字。换句话说,这个算法,它每次都两次自己调用,自己调用,两次递归函数。最终,我们得到了一个指数级的算法。

请注意,指数级的算法是一种非常慢的算法。如果你设计出了一个指数级的算法,就一定要小心。比如说N在20左右,就是百万级的计算量了。如果N在30的时候,普通的计算机转起来就已经非常慢了。其实你是可以对这种进行优化的,比如说进行剪枝操作,再比如说有些指数级算法,可以转化为动态规划等等其他的方法。这样我们就把一个指数级的算法问题,转换成一个多项式级别的算法问题。

functionmergeSort(arr,l,r){if(l>=r){return;}letmid=(l+r)/2mergeSort(arr,l,mid)mergeSort(arr,mid+1,r)merge(arr,l,mid,r)}这是因为在我们之前所举的例子中,我们整棵树的深度是N,而在这些排序搜索中,我们这些树的深度其实是logn的。

那么归并排序、快速排序的算法复杂度是怎么计算的呢?

在这些排序算法中,我们在每个节点中处理的数据规模是逐渐缩小的。而我们之前的例子,每一个节点所处理的数据规模都是一样的,虽然他们都是1,那么大家可以看在右侧,我就画出了。对于归并排序算法,我们要排序8个数字的时候,递归树的形状是怎么样的。

当我们的数组长度为8时,节点树如下:一共logn层,对于每一层的节点,又是O(n)级别的算法。所以,总的算法复杂度是O(nlogn)

在根的地方,我们要处理8个元素,之后,一分为二,每个节点处理四个元素,再一分为二,每个节点处理二个因素,最后一分为二,每个节点处理一个元素,一个元素的时候,我们就不用处理了,因为1个元素不用排序。

那么在我们有8个元素的时候,首先这棵树它的层数不是八层,而是三层。而且每一个节点所处理的数据规模是越来越小的。

那么,这个nlogn怎么来的呢?我们一共有logn这么多层。

所以总体来说,在每一层上,我们处理的数据量也是O(n)这个级别一共有logn层,把它们相乘就得出了onlogn。

THE END
1.Python每日一练:算法的使用指南对数线性时间复杂度:适用于高级排序算法,如归并排序和快速排序。 - 平方时间复杂度:适用于简单排序算法,包括选择排序、插入排序和冒泡排序。 - 立方时间复杂度:适用于Floyd算法和矩阵乘法运算等。 - 几何级数时间复杂度:适用于汉诺塔问题。 - 阶乘时间复杂度:适用于旅行商问题,该问题属于NP完全问题。 https://yun.zjer.cn/index.php?r=space/person/blog/view&sid=172778&id=39543787
2.初阶数据结构常见五大排序算法及部分算法优化讨论再然后我们套上一层循环来控制尾端end的位置,进而实现一组数据的插入排序,因为数组最后的数据是插入到已经有序的数据,所以end要小于n-1(数组最后一个有效数据在n-1),即end最大为n-2。这样最后一个数据插入完,整个数组就有序了。 算法复杂度: 对于直接插入排序来说,从后向前来比较来确定新数据插入的位置,比较https://cloud.tencent.com.cn/developer/article/2476881
3.二叉树的OJ题——6.前序遍历腾讯云开发者社区编程算法二叉树 二叉树先序遍历二叉树先序遍历的实现思想是:访问根节点;访问当前节点的左子树;若当前节点无左子树,则访问当前节点的右子树;二叉树中序遍历二叉树中序遍历的实现思想是:访问当前节点的左子树;访问根节点;访问当前节点的右子树;二叉树后序遍历二叉树后序遍历的实现思想是:从根节点出发,依次遍历各节点https://cloud.tencent.com/developer/article/2477471
4.经典算法150题——多数元素可能最容易想到的一个算法就是 排序,因为多数元素即便是最小的,也会跨越中间下标 n/2, 如果是奇数,就是两个元。 排序后求 nums[n/2] 就行了,考虑奇偶情况处理就行了 但是这种时间复杂度是 O(nlogn) 我们希望有一种 O(n) 的算法 下面这个就是,利用计数器——一个哈希字典,统计每个数的频率并标记当前https://www.jianshu.com/p/af44994479d3
5.2026考研计算机知识点盘点:排序考研(一)排序的基本概念 (二)插入排序 直接插入排序、折半插入排 (三)起泡排序(BubbleSort) (四)简单选择排序 (五)希尔排序(ShellSort) (六)快速排序 (七)堆排序 (八)二路归并排序(MergeSort) (九)基数排序 (十)外部排序 (十一)各种排序算法的比较https://kaoyan.koolearn.com/20241220/1789631.html
6.标题:Dijkstra算法详解及Python实现Dijkstra 算法原理 初始化: 初始化一个字典distances,用于存储从源节点到每个节点的最短距离,初始值为无穷大。 将源节点的初始距离设为 0。 使用一个优先队列queue存储待处理的节点及其当前距离,初始时将源节点及其距离 0 放入队列。 主循环: 从优先队列中取出距离最小的节点及其距离。 https://www.ctyun.cn/zhishi/p-448914
7.未来虫教育线性表的顺序表示和实现loc1、线性表的顺序表示指的是用一组地址连续的存储单元依次存储线性表的数据元素。 2、假设线性表(每个元素占用l个存储单元,并以所占的第一个单元的存储地址作为数据元素的存储位置。则线性表中第i+1个数据元素的存储位置LOC(a(i+1))和第i个数据元素的存储位置LOC(ai)之间满足:LOC(a(i+1))=LOC(ai)+l。https://www.163.com/dy/article/JJD21J7205566XY7.html
8.算法字典序超详细解析(让你有一种相见恨晚的感觉!)? 字典序最小回文串 四、共勉 一、前言 经常刷算法题的朋友,肯定会经常看到题目中提到字典序这样的字眼,或者需要我们通过字典序来解题,由于之前对字典序了解的不太清楚,导致做题的时候总会卡住,所以收集了一些资料来详解字典序。 二、什么是字典序 ? https://blog.csdn.net/weixin_45031801/article/details/137335182
9.python字节序python字符串序列结构网猴儿的技术博客算法分析 KMP算法包括:构造pnext表和匹配。如果模式串和目标串的长度分别为 和 ,KMP算法时间的复杂性是 ,通常情况下 ,因此可认为算法的复杂性为 ,显然优于朴素匹配算法的 19 字符串匹配问题 19.1模式 一个模式描述了(能匹配)一些字符串(一个字符串集合) https://blog.51cto.com/u_14126/7034051
10.算法设计及分析课后习题解答.doc算法设计与分析基础课后练习答案习题1.1 4.设计一个计算的算法,n是任意正整数。除了赋值和比较运算,该算法只能用到基本的四则运算操作。算法求 //输入:一个正整数n2 //输出:。 step1:a=1; step2:若a*an 转step 3,否则输出a; step3:a=a+1转step 2; 5. a.用欧几里德算法求gcd(31415,14142)。 b.https://max.book118.com/html/2017/0904/131756926.shtm
11.算法分析TheAnalysisofAlgorithms算法分析与设计 Analysis and Design of Computer Algorithms 第五章 减治法 Decrease and Conquer 杨春明 西南科学技大学计算机学院 ? School of Computer Science and Technology, SWUST 2 教学内容 ? 减治法的一般方法及变种 ? 插入排序 ? 深度优先查找和广度优先查找 ? 生成组合对象的算法 ? https://doc.mbalib.com/m/view/4ade1e9d6bf94f18b34a4f8a06f5ac8d.html
12.大数据技术原理与应用期末复习知识点全总结(林子雨版3.数据处理与分析层面 功能:利用分布或并行编程模型和计算框架,结合机器学习和数据挖掘算法,实现对海量数据的处理和分析;对分析结果进行可视化呈现,帮助人们更好地理解数据、分析数据 4.数据安全和隐私保护层面 功能:在从大数据中挖掘潜在的巨大商业价值和学术价值的同时,构建隐私数据保护体系和数据安全体系,有效保护个人https://developer.aliyun.com/article/1418435
13.关于全排列的算法问题本文主要通过对全排列以及相关算法的介绍和讲解、分析,让读者更好地了解这一方面的知识,主要涉及到的语言是C和C++。本文的节数:1.全排列的定义和公式:2.时间复杂度:3.列出全排列的初始思想:4.从第m个元素到第n个元素的全排列的算法:5.全排列算法:6.全排列的字典序:7.求下一个字典序https://zhidao.baidu.com/question/1517705957507471380.html
14.GitHub全排列问题,按照字典序递增输出结果。使用数组保存原始输入数据。需要注意题目指出:所给字符串的字母已经按照从小到大的顺序排列。因此为了寻找所有的排列组合,需要不断可以从小到大进行遍历操作。 为了保存每个排列组合,需要另外的数组int ans[MAX_SIZE];保存每次的一个排列组合。 另外回溯法需要不断进行满足边界条件时https://github.com/zpfbuaa/JobduInCPlusPlus
15.Java全排列的几种实现方法java本文详细介绍了Java中全排列问题的几种实现方法,包括回溯法、字典序排列法和迭代法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧+ 目录 全排列问题是一个经典的算法问题,指的是对一个序列中的所有元素生成不重复的排列组合。以下是全排列https://www.jb51.net/program/331407ygn.htm
16.排列的字典序问题字典序算法设计 系统标签: 字典排列getnextseqcoutint序列 排列的字典序问题问题描述:n个元素{1,2,…,n}有n!个不同的排列。将这n!个排列按字典序排列,并编号为0,1,…,n!-1。每个排列的编号为其字典序值。例如,当n=3时,6个不同排列的字典序值如下:字典序值012345排列123132213231312321编程任务:给定n以及https://www.docin.com/p-468923591.html
17.part1集产生5(4)频繁项集产生与剪枝8(5)支持度计数9(6)计算复杂度11关联分析:基本概念和算法http://archive.ic s.uci.edu/ml/datasets.htmlUCI机器学习库基本概念支持度:通常用来删去那些无意义的规则。置信度:估计Y 在给定X下的条件概率。支持度计数:支持度是一个概率,而支持度计数则是该概率上的分子。由关联规http://www.360doc.com/document/18/0623/11/56848932_764615399.shtml