时间复杂度

数据结构:(2)时间复杂度和空间复杂度

僤鯓⒐⒋嵵緔 提交于 2019-12-18 22:10:04
一.算法效率的度量方法 1.事后统计方法: 这种方法主要是通过设计好的测试程序和数据,利用计算机计时器对不同算法编制的程序的运行时间进行比较,从而确定算法效率的高低。 2.事前分析估算方法:在计算机程序编写前,依据统计方法对算法进行估算。 经过总结,一个高级语言编写的程序在计算机上运行时所消耗的时间取决于下列因素: -1.算法采用的策略,方案 -2.编译产生的代码质量 -3.问题的输入规模 -4.机器执行指令的速度 二.函数的渐变增长 1.判断一个算法效率,函数中的常数和其他次要项常常可以忽略,而更应该关注主项(最高项)的阶数。 三.算法时间复杂度 1.算法时间复杂度的定义:在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级。算法的时间复杂度,也就是算法的时间量度,记作:T(n)=O(f(n))。它表示随问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,称作算法的渐进时间复杂度,简称为时间复杂度。其中f(n)是问题规模n的某个函数。 2.如何分析一个算法的时间复杂度呢?即如何推导大O阶呢? -1.用常数1取代运行时间中的所有加法常数。 -2.在修改后的运行次数函数中,只保留最高阶项。 -3.如果最高阶项存在且不是1,则去除与这个项相乘的常数。 -4.得到的最后结果就是大O阶。 3.最坏情况与平均情况:

知识点八:二分查找(上)

ⅰ亾dé卋堺 提交于 2019-12-18 02:27:57
前言 二分查找(Binary Search)算法,也叫折半查找算法,是一种非常简单的查找算法,很多非计算机专业的同学很容易就能理解,但是看似越简单的东西往往越难掌握好,想要灵活应用就更加困难。 老规矩,我们还是来看一道思考题:假设我们有 1000 万个整数数据,每个数据占 8 个字节,如何设计数据结构和算法,快速判断某个整数是否出现在这 1000 万数据中? 我们希望这个功能不要占用太多的内存空间,最多不要超过 100MB,你会怎么做呢? 二分思想 二分查找是一种非常简单易懂的快速查找算法,生活中到处可见。比如说,我们现在来做一个猜字游戏。我随机写一个 0 到 99 之间的数字,然后你来猜我写的是什么。猜的过程中,你每猜一次,我就会告诉你猜的大了还是小了,直到猜中为止。那么如何快速猜中我写的数字呢? 假设我写的数字是 23,你可以按照下面的步骤来试一试(如果猜测范围的数字有偶数个,中间数有两个,就选择较小的那个)。 可以看出,只需要7 次就猜出来了,是不是很快?这个例子用的就是 二分思想 ,按照这个思想,即便我让你猜的是 0 到 999 的数字,最多也只要 10 次就能猜中。不信的话,你可以试一试。 回到实际的开发场景中。假设有 1000 条订单数据,已经按照订单金额从小到大排序,每个订单金额都不同,并且最小单位是元。我们现在想知道是否存在金额等于 19 元的订单。如果存在

图论总结

你。 提交于 2019-12-17 07:43:55
一、最短路   最短路常见算法包括堆优化Dijkstra、Bellman-Ford、SPFA、Floyd。   Dijkstra的时间复杂度为O(mlongn),但是但是不能处理负边权。   基于“松弛”操作(或称三角形不等式)的Bellman-Ford时间复杂度为O(nm),可以处理负边权。队列优化的Bellman-Ford,即SPFA,时间复杂度降到了O(km)(k通常为一个较小的常数),但是在特殊构造的图(比如网格图)中容易退化,因此有的大佬建议尽量不要在正式比赛中使用SPFA。   SPFA也可用于差分约束系统,将在第十部分讲解。   与前三种基于贪心的单源最短路不同,基于动态规划的Floyd是一种多源最短路算法,还可以用于求传递闭包等,但时间复杂度达到了O(n 3 ),无法处理较大的数据。   考场上一般不会考裸的最短路,次短路和最短路计数估计也不常考。我个人觉得真正可能作为考题出现的是最短路树,即由某一点出发的最短路上的边构成的树。众所周知,树拥有许多优秀的性质,也因此常常作为考点。放上几道题:   WOJ #3771 「一本通 3.1 例 1」黑暗城堡(比较裸的最短路树)   WOJ #2423 安全出行Safe Travel(USACO的题)    WOJ#4709 迷路 (某道校内模拟赛题)   最短路也可以与其它算法结合:   WOJ #3841 双调路径

大话数据结构笔记——第二章 算法

夙愿已清 提交于 2019-12-17 01:47:10
第二章 算法 算法 是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作。 算法(Algorithm)这个单词最早出现在波斯数学家阿勒·花刺子密在公元825年(相当于中国的唐朝时期)所写的《印度数字算术》中。 2.1 算法的特性 算法具有5个基本特性:输入、输出、有穷性、确定性和可行性。 2.1.1 输入输出 算法具有零个或多个 输入 。 算法至少有一个或多个 输出 。 2.1.2 有穷性 算法在执行有限的步骤之后,自动结束而不会出现无限循环,并且每一个步骤在可接受的时间内完成。 2.2.3 确定性 算法的每一步骤都具有确定的含义。 2.2.4可行性 算法的每一步都必须是可行的,也就是说,每一步都能够通过执行有限次数完成。 2.2 算法设计的要求 2.2.1 正确性 算法的 正确性 是指算法至少应该具有输入、输出和加工处理无歧义性、能正确反映问题的需求、能够得到问题的正确答案。 分为 四个层次 (层次4验证复杂,代价较高,一般情况下以层次3为判断算法是否正确的标准): 1.算法程序没有语法错误。 2.算法程序对于合法的输入数据能够产生满足要求的输出结果。 3.算法程序对于非法输入数据恩能够得出满足规格说明的结果。 4.算法程序对于精心选择的,甚至刁难的测试数据都有满足要求的输出结果。 2.2.2 可读性 算法设计的另一个目的是为了便于阅读

堆和堆排序:为什么说堆排序没有快速排序快

帅比萌擦擦* 提交于 2019-12-17 00:06:18
“堆(Heap)” 是一种特殊的数。堆这种数据结构的应用场景非常多,最经典的莫过于堆排序了。堆排序是一种原地的、时间复杂度为 O(nlogn) 的排序算法。 快速排序,平均情况下,它的时间复杂度为 O(nlogn)。尽管这两种排序算法的时间复杂度都是 O(nlogn),甚至堆排序比快速排序的时间复杂度还要稳定, 但是,在实际的软件开发中,快速排序的性能要比堆排序好,这是为什么呢? 如何理解“堆”? 前面我们提到,堆是一种特殊的树。我们现在就来看看,什么样的树才是堆。我罗列了两点要求,只要满足这两点,它就是一个堆。 堆是一个完全二叉树; 堆中的每一个节点都大于等于(或者小于等于)其子树中每个节点的值 我分别解释一下这两点。 第一点,堆必须是一个完全二叉树。还记得我们之前讲的完全二叉树的定义吗?完全二叉树要求,除了最后一层,其他层的节点个数都是满的,最后一层的节点都靠左排列。 第二点,堆中的每个节点的值必须大于等于(或者小于等于)其子树中每个节点的值。实际上,我们还可以换一种说法,堆中每个节点的值都大于等于(或者小于等于)其左右子节点的值。这两种表述是等价的。 对于每个节点的值都大于等于子树中每个节点值的堆,我们叫作“大顶堆”。对于每个节点的值都小于等于子树中每个节点值的堆,我们叫作“小顶堆”。 定义解释清楚了,你来看看,下面这几个二叉树是不是堆? 其中第 1 个和第 2 个是大顶堆

浅谈算法和数据结构: 五 优先级队列与堆排序

邮差的信 提交于 2019-12-16 22:29:14
在很多应用中,我们通常需要按照优先级情况对待处理对象进行处理,比如首先处理优先级最高的对象,然后处理次高的对象。最简单的一个例子就是,在手机上玩游戏的时候,如果有来电,那么系统应该优先处理打进来的电话。 在这种情况下,我们的数据结构应该提供两个最基本的操作,一个是返回最高优先级对象,一个是添加新的对象。这种数据结构就是优先级队列(Priority Queue) 。 本文首先介绍优先级队列的定义,有序和无序数组以及堆数据结构实现优先级队列,最后介绍了基于优先级队列的堆排序(Heap Sort) 一 定义 优先级队列和通常的栈和队列一样,只不过里面的每一个元素都有一个”优先级”,在处理的时候,首先处理优先级最高的。如果两个元素具有相同的优先级,则按照他们插入到队列中的先后顺序处理。 优先级队列可以通过链表,数组,堆或者其他数据结构实现。 二 实现 数组 最简单的优先级队列可以通过有序或者无序数组来实现,当要获取最大值的时候,对数组进行查找返回即可。代码实现起来也比较简单,这里就不列出来了。 如上图: · 如果使用无序数组,那么每一次插入的时候,直接在数组末尾插入即可,时间复杂度为O(1),但是如果要获取最大值,或者最小值返回的话,则需要进行查找,这时时间复杂度为O(n)。 · 如果使用有序数组,那么每一次插入的时候,通过插入排序将元素放到正确的位置,时间复杂度为O(n)

如何提升你的数据结构、算法以及解决问题的能力

雨燕双飞 提交于 2019-12-16 15:05:37
如何提升你的数据结构、算法以及解决问题的能力 这篇文章借鉴了我过去在学校一个学期的个人经历和挑战,当我进入学校的时候,我对任何 DSA(数据结构和算法)和解决问题的策略几乎一无所知。作为一名自学成才的程序员,我对一般编程会更加熟悉和舒适,例如面向对象编程,而不是 DSA 问题所需要的解决问题的能力。 这篇文章反映了我整个学期的经历,并包含了为了快速提高数据结构、算法和解决问题的能力而求助的资源。 面临问题:你知道原理,但是你被实际应用卡住了 我在学期初期的时候遇到这个问题,当时我不明白我哪里不懂,这是一个特别严重的问题。我对这个理论很了解,例如,什么是链表,它是如何工作的,它的各种操作和时间复杂度,它支持的 ADT(抽象数据类型),以及如何实现 ADT 操作。 但是,由于我不明白我哪里不懂,所以我无法确定我对它的理解和在实际应用中解决问题的差距。 不同类型的问题 一个数据结构问题的例子:描述如何在链表中插入一个节点并说明时间复杂度。 这是一个算法问题:在旋转数组中查找元素并说明时间复杂度。 最后是解决问题的疑虑,我认为比之前两个问题的级别更高,这可能需要简要描述一个场景,并且列出问题的要求。在考试中,可能会要求你对解决方案进行描述。在编程比赛中,可能会要求你在不明确提供任何的数据结构和算法的情况下提交可运行的代码。换句话说

leetcode-16. 最接近的三数之和

瘦欲@ 提交于 2019-12-16 11:42:47
题目 给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。 例如,给定数组 nums = [-1,2,1,-4], 和 target = 1. 与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2). 思路 标签:排序和双指针 本题目因为要计算三个数,如果靠暴力枚举的话时间复杂度会到 O(n^3) ,需要降低时间复杂度 首先进行数组排序,时间复杂度 O(nlogn) 在数组 nums 中,进行遍历,每遍历一个值利用其下标i,形成一个固定值 nums[i] 再使用前指针指向 start = i + 1 处,后指针指向 end = nums.length - 1 处,也就是结尾处 根据 sum = nums[i] + nums[start] + nums[end] 的结果,判断 sum 与目标 target 的距离,如果更近则更新结果 ans 同时判断 sum 与 target 的大小关系,因为数组有序,如果 sum > target 则 end--,如果 sum < target 则 start++,如果 sum == target 则说明距离为 0 直接返回结果 整个遍历过程,固定值为 n 次,双指针为 n 次,时间复杂度为

线性排序:如何根据年龄给100W用户数据排序

三世轮回 提交于 2019-12-16 09:21:16
线性排序:如何根据年龄给100W用户数据排序 桶排序、计数排序、基数排序,因为这些算法的时间复杂度是线性的,所以叫做线性排序,之所以能做到线性的时间复杂度,是因为这三个算法是基于比较的排序算法,都不涉及元素之间的比较操作 重点是掌握这些排序算法的适用场景 桶排序(bucket sort) 核心思想是将要排序的数据分到几个有序的桶里,每个桶里的数据再单独进行排序,桶内排完序之后,再把每个桶里面的数据按照顺序依次取出,组成的序列就是有序的 桶排序的时间复杂度是O(n):如果要排序的数据有n个,把它们均匀的划分到m个桶内,每个桶里就有k = n/m个元素,每个桶内部使用快排,时间复杂度为O( k ∗ l o g k k*logk k ∗ l o g k ),m个桶就是O( m ∗ k ∗ l o g k m*k*logk m ∗ k ∗ l o g k ),因为k=n/m,所以m个桶即整个桶的时间复杂度是O( n ∗ l o g ( n / m ) n*log(n/m) n ∗ l o g ( n / m ) ),当桶的个数m接近数据个数n时,log(n/m)就是一个非常小的常量,桶排序的时间复杂度接近O(n) 桶排序看起来很优秀,但是不能替代之前的排序算法,因为桶排序对排序数据的要求很苛刻,首先,要排序的数据需要很容易划分成m个桶,并且,桶与桶之间有天然的大小顺序

【算法笔记】跳表

橙三吉。 提交于 2019-12-16 05:01:21
跳表 1.如何理解“跳表”? 2.用跳表查询到底有多快?-时间复杂度 3.跳表是不是很浪费内存?-空间复杂度 4 高效的动态插入和删除 5 跳表索引动态更新 6 为什么 Redis 要用跳表来实现有序集合,而不是红黑树? 7 总结 1.如何理解“跳表”? 这种链表加多级索引的结构,就是跳表; 2.用跳表查询到底有多快?-时间复杂度 每两个结点会抽出一个结点作为上一级索引的结点,那第一级索引的结点个数大约就是 n/2,第二级索引的结点个数大约就是 n/4,第三级索引的结点个数大约就是 n/8,依次类推,也就是说,第 k 级索引的结点个数是第 k-1 级索引的结点个数的 1/2,那第 k级索引结点的个数就是 n/(2^k)。 假设索引有 h 级,最高级的索引有 2 个结点。通过上面的公式,我们可以得到 n/(2^h)=2,从而求得 h=log2n-1。如果包含原始链表这一层,整个跳表的高度就是 log2n。我们在跳表中查询某个数据的时候,如果每一层都要遍历 m 个结点,那在跳表中查询一个数据的时间复杂度就是 O(m*logn)。 每一级索引都最多只需要遍历 3 个结点,也就是说 m=3; m=3的详细解释: 假设我们要查找的数据是 x,在第 k 级索引中,我们遍历到 y 结点之后,发现 x 大于 y,小于后面的结点 z,所以我们通过 y 的 down 指针,从第 k 级索引下降到第 k