时间复杂度

[洛谷P4213]【模板】杜教筛(Sum)(杜教筛讲解)

烈酒焚心 提交于 2020-02-10 18:19:49
题面 https://www.luogu.com.cn/problem/P4213 题解 前置知识 线性筛积性函数: https://www.cnblogs.com/zhoushuyu/p/8275530.html 莫比乌斯反演:《具体数学:计算机科学基础》4.9节 数论分块: https://www.cnblogs.com/xh092113/p/12269753.html 杜教筛 对于一些数论函数,杜教筛可以在低于线性的时间复杂度内求出其前缀和。 适用范围:对于数论函数f,g,h,如果g、h的前缀和能够 \(O(1)\) 求解,并且有 \[h=f{\times}g\] (其中 \({\times}\) 表示狄利克雷卷积) 那么,我们可以在低于线性的时间复杂度内求出f的前缀和。原理如下:(以下sf,sg,sh分别表示f,g,h的前缀和) \[h(n)={\sum\limits_{d1d2=n}}f(d1)g(d2)\] \[{\sum\limits_{i=1}^{n}}h(i)={\sum\limits_{d1d2{\leq}n}}f(d1)g(d2)\] \[sh(i)={\sum\limits_{d2=1}^{n}}g(d2){\sum\limits_{d1=1}^{{\lfloor}{\frac{n}{d1}}{\rfloor}}}f(d1)\] \[={\sum

二叉树和哈希表的优缺点对比与选择

佐手、 提交于 2020-02-10 09:12:03
二叉树(binary tree)和哈希表(hash table)都是很基本的数据结构,但是我们要怎么从两者之间进行选择呢?他们的不同是什么?优缺点分别是什么? 回答这个问题不是一两句话可以说清楚的,原因是在不同的情况下,选择的依据肯定也不同。首先来回顾一下这两个数据结构: 哈希表使用hash function来对输入的数据分配index到哈希表对应的槽中。假设有一个哈希表的size是100,而我们输入的数据是从0~99,我们要把输入数据储存到哈希表中。理论上来说,该哈希表插入和查找操作的时间复杂度都是O(1)。 二叉树遵循右子树大于根节点,左子树小于根节点的原则进行数据的插入和保存。如果这个树的 平衡 的,那么,对于每个元素的插入和查找操作的时间复杂度是O(log(n)),n是树的节点个数,log(n)通常是树的深度。当然,对于不平衡的情况,那就需要更复杂的数据结构的树(红黑树等)进行处理。 上文似乎得出结论哈希表要好于二叉树,但是it is not always the case。哈希表有以下几个突出的缺点: 当更多的数插入时,哈希表冲突的可能性就更大。对于冲突,哈希表通常有两种解决方案:第一种是线性探索,相当于在冲突的槽后建立一个单链表,这种情况下,插入和查找以及删除操作消耗的时间会达到O(n),且该哈希表需要更多的空间进行储存。第二种方法是开放寻址,他不需要更多的空间

归并排序

社会主义新天地 提交于 2020-02-09 01:29:56
归并排序 定义 归并排序是采用分治法的一个非常典型的应用。归并排序的思想就是先递归分解数组,再合并数组。将数组分解最小之后,然后合并两个有序数组,基本思路是比较两个数组的最前面的数,谁小就先取谁,取了后相应的指针就往后移一位。然后再比较,直至一个数组为空,最后把另一个数组的剩余部分复制过来即可 算法描述 把长度为n的输入序列分成两个长度为n/2的子序列; 对这两个子序列分别采用归并排序; 将两个排序好的子序列合并成一个最终的排序序列。 代码实现 def merge_sort ( alist ) : if len ( alist ) <= 1 : return alist # 二分分解 num = len ( alist ) / 2 left = merge_sort ( alist [ : num ] ) right = merge_sort ( alist [ num : ] ) # 合并 return merge ( left , right ) def merge ( left , right ) : '''合并操作,将两个有序数组left[]和right[]合并成一个大的有序数组''' #left与right的下标指针 l , r = 0 , 0 result = [ ] while l < len ( left ) and r < len ( right ) : if

[数据结构与算法 03] 最好、最坏、平均、均摊 时间复杂度

荒凉一梦 提交于 2020-02-09 01:29:34
由来 /**** 在一个无序的数组(array)中 查找变量 x 第一次出现的位置。如果没有找到,就返回 -1 ****/ // n 表示数组array的长度 int find(int[] array, int n, int x) { int i = 0; int pos = -1; for (; i < n; ++i) { if (array[i] == x) pos = i; } return pos; } 分析出此函数的时间复杂度为 O(n) 在数组中查找一个数据,并不需要每次都把整个数组都遍历一遍, 因为有可能中途找到就可以提前结束循环了。 所以我们可以这样优化一下这段查找代码 /**** 在一个无序的数组(array)中 查找变量 x 第一次出现的位置。如果没有找到,就返回 -1 ****/ // n 表示数组array的长度 int find(int[] array, int n, int x) { int i = 0; int pos = -1; for (; i < n; ++i) { if (array[i] == x) { pos = i; break; // 已经找到了,就不必继续找了 } } return pos; } 那么问题来了,如此优化以后,时间复杂度还是 O(n) 吗??? 可能第一次就找到了,只循环了一次,那时间复杂度就是 O(1)

数据结构 耿国华老师讲

依然范特西╮ 提交于 2020-02-08 22:05:38
第一章$绪论 第一讲$数据结构的基础 数据是表征客观事物的可记录可识别的符号集合。数据是信息处理的核心基础。 数据结构有关的基本概念术语: 1.数据 2.数据元素 3.数据对象 4.数据类型 5.数据类型 6.抽象数据类型 7.数据结构 数据结构是指相互之间存在一种或多种特定关系的数据元素集合。它强调的是带有结构的数据元素的集合,数据元素之间的相互关系,即数据的组织形式。数据的组织方法与效率密切相关,采用不同数据的组织方法其处理效率不同。 第二讲$数据结构的内容简介 数据结构的内容,即数据结构研究范围:逻辑结构、存储结构、运算集合。数据结构注重的是数据元素之间的相互关系。 数据元素的相互关系表示为数据元素间的逻辑关系即逻辑结构。数据元素之间存在四种基本的逻辑结构: 1.集合结构 2.线性结构 3.树形结构 4.图形结构 数据元素之间关系在计算机中的表示方法分为: 顺序映象 (顺序存储结构,如数组,就是一组连续配置的单元); 非顺序映象 (非顺序存储结构,如链表,是一组任意配置的单元,通过指针连接起来,维持逻辑关系)。 第三讲$数据结构与C语言…… 一本正经划水总结一下(咳咳) 当需要用一个形式参数直接改变对应实参的值时,改形式参数应说明为:与实参同类型指针参数。 第四讲$算法性能评价 算法性能评价指标算法的执行时间,和占用空间两个方面,通过引入问题规模,语句频度等概念

时间复杂度

╄→гoц情女王★ 提交于 2020-02-08 17:30:20
时间复杂度:用来评估算法运行效率的一个式子 先看下面栗子感受一下 Debug.log("ok");//0(1) foreach (var item in collection) { Debug.log("ok");//0(1) }//0(n) foreach (var item in collection) { foreach (var item in collection) { Debug.log("ok");//0(1) }//0(n) }//0(n^2) 再看这个 foreach (var item in collection) { Debug.log("ok");//0(1) foreach (var item in collection) { Debug.log("ok");//0(1) }//0(n) } 按道理来说应该是 (n+1)*n=n^2+n,但是其实还是o(n^2),因为时间复杂度只是估算,所以只取最高项,而且常数忽略, 比如3n^2+n+5=n^2 再看下面的 while (n>1) { Debug.log(n);//0(1) n =n / 2;//0(1) } 如果n=64,循环执行6次,也就是2^6=64,那么时间复杂度就是O(logn),记住了只要出现折半操作的循环,必定是对数时间复杂度,比如二叉树,快速排序等等 给个表 稳定性是指

java算法----算法的时间复杂度

独自空忆成欢 提交于 2020-02-08 04:52:20
一. 度量一个程序(算法)执行时间的两种方法 1.事后统计的方法 这种方法可行,但有两个问题: 一是想要对设计的算法的运行性能进行评测,需要实际运行改程序; 二十所得时间的统计量依赖于计算机硬件, 软件等环境因素, 这种方式, 要在同一台计算机的相同状态下运行,才能比较哪个算法速度更快. 2.事前估算的方法 通过分析算法的 时间复杂度 来判断哪个算法更占优 二. 从时间频度到时间复杂度 1.时间频度 一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但我们不可能也没有必要对每个算法都上机测试,只需知道哪个算法花费的时间多,哪个算法花费的时间少就可以了。并且一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。 一个算法中的语句执行次数称为语句频度或时间频度 。记为T(n),n表示语句的执行次数。 时间频度案例说明: 2.时间复杂度 前面提到的时间频度T(n)中,n称为问题的规模,当n不断变化时,时间频度T(n)也会不断变化。但有时我们想知道它变化时呈现什么规律,为此我们引入时间复杂度的概念。 一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数,记作T(n)=O

数据结构与算法(冒泡排序)

↘锁芯ラ 提交于 2020-02-07 23:36:40
冒泡排序 冒泡排序是一种简单的排序算法。它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把它们交换过来。遍历数列的工作是重复的进行直到没有在需要的交换,也就是说该数列已经排序完成,这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。 冒泡算法的运作如下: 比较相邻的元素,如果第一个元素大于第二个元素(升序),就交换它们两个。 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对,这步完成后,最后的元素会是最大的数。 针对所有的元素重复以上的步骤,除了最后一个 持续每次越来越少的元素重复上面的步骤,直到没有任何一堆数字需要比较。 冒泡算法分析 交换过程图示( 第一次 ): 那么我们需要进行n-1次冒泡过程,每次对应的比较次数如下图所示: Pass Comparisons 1 n-1 2 n-2 3 n-3 … … n-1 1 代码实现 def bubble_sort(alist): """冒泡排序""" for j in range(len(alist)-1): for i in range(len(alist)-j-1): if alist[i] > alist[i+1]: alist[i], alist[i+1] = alist[i+1], alist[i] return alist 时间复杂度 最优时间复杂度:O(n

十大经典排序排序算法学习总结(C++实现)

倖福魔咒の 提交于 2020-02-07 21:48:55
常用算法总结记录一下,否则会变得只记得算法名,也可能名都记不住。 图片和动图(我不会画),但我从网上找到了资源。 代码我用C/C++实现的,运行结果都有验证。 时间复杂度和空间复杂度我还没有研究,各种地方抄到的,以后有时间再研究,如果有错误,还请指正。   In/out-place: 不占/占额外内存 1.冒泡排序  冒泡排序算法原理:   比较相邻的元素。如果第一个比第二个大,就交换他们两个。   循环重复以上步骤,直到没有任何一对元素需要比较。   还有位前辈也画的挺好,我也把图贴过来了。  冒泡排序时间复杂度、空间复杂度、稳定性   冒泡排序时间复杂度:最好 O( n) 最坏 O( n 2 ) ,平均 O( n 2 ) 。   冒泡排序空间复杂度: O( 1 ) 。   冒泡排序是一种 稳定 排序算法。  冒泡排序源码实现 1 #include <iostream> 2 using namespace std; 3 4 5 template <typename T> 6 void BubbleSort(T arr[], int len) 7 { 8 if (NULL == arr || 0 >= len) 9 return; 10 11 int i = 0, j = 0, nFlag = 0; 12 13 for (i = 0; i < len - 1; i++) 14 {

O(1), O(n), O(logn), O(nlogn)

只愿长相守 提交于 2020-02-07 01:35:44
由于平时接触算法比较少,今天看资料看到了O(1),都不知道是什么意思,百度之后才知道是什么意思。 描述算法复杂度时,常用O(1), O(n), O( l o g n logn l o g n ), O( n l o g n nlogn n l o g n )表示对应算法的时间复杂度,是算法的时空复杂度的表示。不仅仅用于表示时间复杂度,也用于表示空间复杂度。 O后面的括号中有一个函数,指明某个算法的耗时/耗空间与数据增长量之间的关系。其中的n代表输入数据的量。 比如时间复杂度为O(n),就代表数据量增大几倍,耗时也增大几倍。比如常见的遍历算法。再比如时间复杂度O( n 2 n^2 n 2 ),就代表数据量增大n倍时,耗时增大n的平方倍,这是比线性更高的时间复杂度。比如冒泡排序,就是典型的O( n 2 n^2 n 2 )的算法,对n个数排序,需要扫描n×n次。 再比如O( l o g n logn l o g n ),当数据增大n倍时,耗时增大 l o g n logn l o g n 倍(这里的log是以2为底的,比如,当数据增大256倍时,耗时只增大8倍,是比线性还要低的时间复杂度)。二分查找就是O( l o g n logn l o g n )的算法,每找一次排除一半的可能,256个数据中查找只要找8次就可以找到目标。 O( n l o g n nlogn n l o g n