时间复杂度

时间复杂度分析

三世轮回 提交于 2020-02-27 00:30:38
时间复杂度分析 大O表示法 O(1): Constant Complexity 常数复杂度 int n = 1000; System.out.println("Hey - your input is: " + n); int n = 1000; System.out.println("Hey - your input is: " + n); System.out.println("Hmm.. I'm doing more stuff with: " + n); System.out.println("And more: " + n); O(log n): Logarithmic Complexity 对数复杂度 for (int i = 1; i < n; i = i * 2) { System.out.println("Hey - I'm busy looking at: " + i); } O(n): Linear Complexity 线性时间复杂度 for (int i = 1; i <= n; i++) { System.out.println("Hey - I'm busy looking at: " + i); } O(n^2): N square Complexity 平方 for (int i = 1; i <= n; i++) { for (int j = 1;

数据结构与算法初步认识

不羁岁月 提交于 2020-02-26 21:44:23
文章来源: http://blog.seclibs.com/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95%E5%88%9D%E6%AD%A5%E8%AE%A4%E8%AF%86-2/ 什么是数据结构和算法 数据结构和算法经常是结合在一起的东西,数据结构是数据的存储方式,而算法是对数据的具体操作,他们二者是相辅相成的,数据结构是为算法服务的,算法是要作用在特定的数据结构之上的,两者是不可以孤立存在的。 在平时我们所遇到的数据结构和算法有以下一些 整个列表的内容下来还是非常多的,这里不立什么flag,只是为了给之后所学习的内容做一个更好的铺垫。 数据结构和算法的应用就是为了解决程序的快和省的问题,即运行的够快,占用的空间够少,在评比这两项内容的时候,我们引入了时间复杂度和空间复杂度两个复杂度的概念。虽然说我们可以在写完程序后对程序的时间进行计算和统计等,但那属于事后统计法,有一种事后诸葛亮的感觉,我们需要的是在写程序的时候就对整体的复杂性有一个大概的评估。 这里我们引入的是大O表示法,T(n)=O(f(n)),其中,T(n) 表示代码执行的时间;n 表示数据规模的大小;f(n) 表示每行代码执行的次数总和。因为这是一个公式,所以用 f(n) 来表示。公式中的 O,表示代码的执行时间 T(n) 与 f(n)

线性表和链表的比较

谁都会走 提交于 2020-02-26 19:13:22
区别 1、存取(读写)方式 顺序表可以顺序存取,也可以随机存取;链表只能从表头顺序存取元素。 例如:在第 i 个位置上执行存取操作,顺序表只需访问一次,而链表则需要从表头开始依次访问 i 次。 2、逻辑结构与物理结构 采用顺序存取时,逻辑结构上相邻的元素,对应的物理存储位置也是相邻的;而采用链式存储时,逻辑结构上相邻的元素,物理存储位置则不一定相邻,对应的逻辑关系也是通过指针链接来表示的。 3、查找,插入和删除操作 对于按值查找,顺序表无序时,两者的时间复杂度均为O(n);当顺序表有序时,可采用折半查找,此时的时间复杂度为0(log2n); 对于按序号查找,顺序表支持随机访问,时间复杂度仅为O(1),而链表的平均时间复杂度为O(n); 顺序表的插入,删除操作,平均需要移动半个表长的元素,链表的插入,删除操作,只需要修改相关结点的指针域即可,由于链表的每个结点都带有指针域,故其存储密度不够大。 4、空间分配 顺序存储在静态存储分配情形下,一旦存储空间装满就不能扩充了,若要再加入新的元素,则会出现内存溢出,因此需要预先分配存储空间;若预先分配空间过大,可能会导致顺序表后部大量闲置,若预先分配空间过小,又会造成溢出;动态存储分配虽然存储空间可以扩充,但是需要移动大量元素,导致操作效率降低,而且若内存中没有更大块的连续存储空间,则会导致分配失败;链式存储的结点空间只在需要的时申请分配

返回一个整数数组中最大子数组的和(1)

纵饮孤独 提交于 2020-02-26 18:48:41
题目要求: 输入一个整形数组,数组里有正数也有负数。 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。 求所有子数组的和的最大值。要求时间复杂度为O(n) 发表一篇博客文章讲述设计思想,出现的问题,可能的解决方案(多选)、源代码、结果截图、总结。 设计思想及代码和结果截图: 1.最开始的想法很简单,使用穷举法。我们列出所有的子数组之和,然后取出其中的最大值,代码如下: public static void main(String[] args) { int [] a = {1,-2,3,10,-4,7,2,-5}; int maxsofar = 0; int sum = 0; //进入循环 for(int i=0;i<8;i++) { sum=0; //每次求出一个子数组的和就和目前的最大值进行比较 for(int j=i;j<8;j++) { sum+=a[j]; maxsofar = Math.max(maxsofar, sum); } } System.out.println(maxsofar); } 运行结果如图: 可以看到,结果是正确的,但这个的时间复杂度为O(n2),明显超出了我们题目要求的O(n),通常最直观的算法是最慢的,我们接着使用别的算法。 2.之后,意识到老师提出的动态规划算法,于是在网上查阅了相关资料,发现了Kadane算法

LinkedList与ArrayList的区别

扶醉桌前 提交于 2020-02-26 14:43:03
LinkedList与ArrayList的区别: 1 、 因为Array是基于索引(index)的数据结构,它使用索引在数组中搜索和读取数据是很快的,可以直接返回数组中index位置的元素,因此在随机访问集合元素上有较好的性能。Array获取数据的时间复杂度是O(1),但是要插入、删除数据却是开销很大的,因为这需要移动数组中插入位置之后的的所有元素。ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。 (LinkedList是双向链表,有next也有previous) 2 、相对于ArrayList,LinkedList的随机访问集合元素时性能较差,因为需要在双向列表中找到要index的位置,再返回;但在插入,删除操作是更快的。因为LinkedList不像ArrayList一样,不需要改变数组的大小,也不需要在数组装满的时候要将所有的数据重新装入一个新的数组,这是ArrayList最坏的一种情况,时间复杂度是O(n),而LinkedList中插入或删除的时间复杂度仅为O(1)。ArrayList在插入数据时还需要更新索引(除了插入数组的尾部)。 3 、LinkedList需要更多的内存,因为ArrayList的每个索引的位置是实际的数据,而LinkedList中的每个节点中存储的是实际的数据和前后节点的位置。 4 、对于随机访问get和set

数据结构与算法:链表

谁都会走 提交于 2020-02-26 10:29:37
一、链表和数组的区别 链表与数组相似,但链表是一种比数组稍微复杂的数据结构。数组需要一块连续的内存空间来存储数据,对内存的要求比较高,而链表则不需要,它通过「指针」将不连续的内存块串联起来。如果要申请一个 100MB 大小的数组和链表,当内存中没有连续的,或者没有足够大小的空间时,数组便会申请失败,而链表不会。 链表有很多种结构,常见的有: 单链表 、 双向链表 、 循环链表 。 二、单向链表 链表通过指针将不连续的内存块串联在一起使用,我们把其中的内存块称为「结点」,而为了将所有的结点串起来,链表中的结点除了存储数据之外,还会用指针记录链表结点的下一个结点的地址,我们把这个记录下一个结点的地址的指针叫做「后继指针next」,整个单链表如下图所示。 其中第一个结点和最后一个结点是比较特殊的,通常分别把它们称为「头结点」和「尾结点」。头结点用来记录链表的基地址,有了它就能遍历得到整个链表。尾结点并不指向任何结点,而是指向空地址 null ,表示链表上的最后一个结点。 与数组不同,链表的插入和删除操作并不需要大量的数据搬移,它只需要考虑相邻结点的指针改变,对应的时间复杂度为 O(1) 。同样,链表的访问元素操作也没有数组那样直接用首地址和下标通过寻址公式直接得到对应的内存地址,链表需要通过从指针一个一个结点地遍历,直到找到相应的结点。因此链表的随机访问时间复杂度为 O(n) 。 三

算法之二分查找(上)

送分小仙女□ 提交于 2020-02-26 09:44:29
文章来源: http://blog.seclibs.com/算法之二分查找上/ 二分查找在平时的生活中也挺常用的,比如说以前玩的猜数游戏,每次都取中间数,然后得知是大了,还是小了,这个例子也就是二分查找。 比如下面的这个例子,要查找有没有数值19,其中low和high是查找的区间的下标,mid是查找区域的中间值的下标。 二分查找的思想是比较容易理解的,而且它的时间复杂度也是比较低的。假设数据大小为n,每次查找完后都会缩小一半,即为除以2,最坏的情况也就是一直到查找空间为空的时候,所以它们的变化为n,n/2,n/4,n/8,…,n/2k,当n/2k=1时,k即为缩小的次数,因为每次都只涉及到两个数的大小比较,所以k次操作的时间复杂度为O(k),又因为n/2k=1,所以k=log2n,时间复杂度也就是O(logn),这是一个非常恐怖的数量级了,比如n为2的32次方,大约是四十多亿,用二分查找来查找里面的一个数的话,最多比较32次也就可以得到这个值了,这是一个非常恐怖的情况。 上面的原理已经很明确了,所以二分查找的实现并不是很复杂,但是有一个前提条件,有序数组中不存在重复元素,只有在这个情况下,二分查找的实现才是相对简单的,具体的实现在下一篇文章里提及。 虽然二分查找时间复杂度低,查找起来非常高效,但它也有一定的适用条件的。 首先,二分查找是依赖于数组的,如果使用其他的数据结构来实现的话

【从0到1学算法】大O表示法

偶尔善良 提交于 2020-02-26 03:36:50
一般我们在选择算法时,都是想要选择效率最高的算法。那算法的效率,用什么表示?没错!就是用大O表示法。 PS : 大O表示法中,log即为log2,后面不再说明。 下面以简单查找和二分查找,在含有n个元素的有序列表中查找其中一个元素为例,下表总结了我们发现的情况。 使用简单查找时,最多需要猜测次数与列表长度相同,这被称为线性时间,大O表示法为O(n)。 二分查找则不同,最多需要猜测次数为logn(n为列表长度),这被称为对数时间(log时间),大O表示法为O(logn)。 基本概念 大O表示法指出了算法的速度有多快。 可能你会好奇,它的单位是多少?秒?没有单位,它并非指的是时间,而是从增量的角度衡量。 列表中查找元素,简单查找、二分查找的增速如下图。 假若我们不知道增速,只知道查找100个元素时的查找时间,猜测10000个元素时的查找时间: 对于简单查找,100个元素时为100毫秒,简单推算出10000个元素为10秒; 对于二分查找,100个元素时为7毫秒,简单推算出10000个元素为700毫秒。 PS:简单推算 10000个元素时的运行时间= 运行时间(100个元素时)* 100 简单查找的推算是对的,因为的增速是n,而二分查找的推算是错的,它的增速为logn,这便不能理所当然简单推算了。 很显然,我们只要知道算法的增速,便能知道它在n个元素中运行的运行时间了

《C语言》 —— 数组详解

久未见 提交于 2020-02-26 03:05:41
书籍使我变成了一个幸福的人,使我的生活变成轻松而舒适的诗。——高尔基 本文已经收录至我的GitHub,欢迎大家踊跃star 和 issues。 https://github.com/midou-tech/articles 前言  我本来准备C语言章节就写个指针就ok了,在我看来C语言的精华部分就是指针了。但是有很多同学就开始在群里各种拉扯C语言的其他问题,没办法,我是龙叔嘛,想想还是整理一下,把一些重要的C语言知识点都一一更新了吧。C语言指针的内容请点击 指针(上) 和 指针(下) , 记得点关注,不迷路 数组的基本概念  我们把一组数据的集合称为 数组(Array) ,它所包含的每一个数据叫做 数组元素 (Element),所包含的数据的个数称为 数组长度 (Length),数组中的每个元素都有一个序号,这个序号从0开始,而不是从我们熟悉的1开始,称为 下标 (Index),所包含数组的里面元素的类型叫做 数组类型 (Type)。  一句话就说清楚了数组的基本概念,就是这么简单,^_^。 数组底层结构探析 int array[5]; 内存布局图  不要看这个图简单,底层就是这样的。数组是一个整体,它的内存是 连续 的;也就是说,数组元素之间是相互挨着的,彼此之间没有一点点缝隙。   这一点很重要,连续的内存为 指针 操作(通过指针来访问数组元素)和内存处理(整块内存的复制、写入等

lintcode-65-两个排序数组的中位数

亡梦爱人 提交于 2020-02-26 02:30:16
65-两个排序数组的中位数 两个排序的数组A和B分别含有m和n个数,找到两个排序数组的中位数,要求时间复杂度应为O(log (m+n))。 样例 给出数组A = [1,2,3,4,5,6] B = [2,3,4,5],中位数3.5 给出数组A = [1,2,3] B = [4,5],中位数 3 挑战 时间复杂度为O(log n) 标签 分治法 排序数组 数组 谷歌 Zenefits 优步 思路 参考 http://www.cnblogs.com/grandyang/p/4465932.html 这道题让我们求两个有序数组的中位数,而且限制了时间复杂度为O(log (m+n)),看到这个时间复杂度,自然而然的想到了应该使用二分查找法来求解。但是这道题被定义为Hard也是有其原因的,难就难在要在两个未合并的有序数组之间使用二分法,这里我们需要定义一个函数来找到第K个元素,由于两个数组长度之和的奇偶不确定,因此需要分情况来讨论,对于奇数的情况,直接找到最中间的数即可,偶数的话需要求最中间两个数的平均值。下面重点来看如何实现找到第K个元素,首先我们需要让数组1的长度小于或等于数组2的长度,那么我们只需判断如果数组1的长度大于数组2的长度的话,交换两个数组即可,然后我们要判断小的数组是否为空,为空的话,直接在另一个数组找第K个即可。还有一种情况是当K = 1时,表示我们要找第一个元素