集束搜索(又名定向搜索,BeamSearch)——最佳优先搜索算法的优化。
A*搜寻算法——图形搜索算法,是最佳优先搜索的范例,从给定起点到给定终点计算出路径。
数据压缩——采取特定编码方案,使用更少的字节数(或是其他信息承载单元)对信息编码的过程,又叫来源编码。
离散微分算法(Discretedifferentiation)
哈希算法(Hashing)
堆排序(Heaps)
合并排序(MergeSort)
梯度下降(Gradientdescent)——一种数学上的最优化算法。
牛顿法(Newton'smethod)——求非线性方程(组)零点的一种重要的迭代法。
欧几里得算法(Euclideanalgorithm)——计算两个整数的最大公约数。最古老的算法之一,出现在公元前300前欧几里得的《几何原本》。
Buchberger算法——一种数学算法,可将其视为针对单变量最大公约数求解的欧几里得算法和线性系统中高斯消元法的泛化。
动态规划算法(DynamicProgramming)——展示互相覆盖的子问题和最优子架构算法。
Diffie-Hellman密钥交换算法——一种加密协议,允许双方在事先不了解对方的情况下,在不安全的通信信道中,共同建立共享密钥。该密钥以后可与一个对称密码一起,加密后续通讯。
Dijkstra算法——针对没有负值权重边的有向图,计算其中的单一起点最短算法。
二分查找(BinarySearch)——在线性数组中找特定值的算法,每个步骤去掉一半不符合要求的数据。
合并查找算法(Union-find)——给定一组元素,该算法常常用来把这些元素分为多个分离的、彼此不重合的组。
期望-最大算法(Expectation-maximizationalgorithm,又名EM-Training)——在统计计算中,期望-最大算法在概率模型中寻找可能性最大的参数估算值,其中模型依赖于未发现的潜在变量。
快速傅里叶变换(FastFouriertransform,FFT)——计算离散的傅里叶变换(DFT)及其反转。
最大流量算法(Maximumflow)——该算法试图从一个流量网络中找到最大的流。
LLL算法(Lenstra-Lenstra-Lovaszlatticerection)——以格规约(lattice)基数为输入,输出短正交向量基数。
两次筛法(QuadraticSieve)——现代整数因子分解算法,在实践中,是目前已知第二快的此类算法(仅次于数域筛法NumberFieldSieve)。
RANSAC——是“RANdomSAmpleConsensus”的缩写。该算法根据一系列观察得到的数据,数据中包含异常值,估算一个数学模型的参数值。
求解线性方程组()——线性方程组是数学中最古老的问题,它们有很多应用,比如在数字信号处理、线性规划中的估算和预测、数值分析中的非线性问题逼近等等。求解线性方程组,可以使用高斯—约当消去法(Gauss-Jordanelimination),或是柯列斯基分解(Choleskydecomposition)。
Q-learning学习算法——这是一种通过学习动作值函数(action-valuefunction)完成的强化学习算法,函数采取在给定状态的给定动作,并计算出期望的效用价值,在此后遵循固定的策略。
Schönhage-Strassen算法——在数学中,Schönhage-Strassen算法是用来完成大整数的乘法的快速渐近算法。其算法复杂度为:O(Nlog(N)log(log(N))),该算法使用了傅里叶变换。
RSA——公钥加密算法。首个适用于以签名作为加密的算法。RSA在电商行业中仍大规模使用,大家也相信它有足够安全长度的公钥。
Strukturtensor算法——应用于模式识别领域,为所有像素找出一种计算方法,看看该像素是否处于同质区域(homogenousregion),看看它是否属于边缘,还是是一个顶点。
单纯型算法(SimplexAlgorithm)——在数学的优化理论中,单纯型算法是常用的技术,用来找到线性规划问题的数值解。
奇异值分解(Singularvaluedecomposition,简称SVD)——在线性代数中,SVD是重要的实数或复数矩阵的分解方法,在信号处理和统计中有多种应用,比如计算矩阵的伪逆矩阵(以求解最小二乘法问题)、解决超定线性系统(overdeterminedlinearsystems)、矩阵逼近、数值天气预报等等。
维特比算法(Viterbialgorithm)——寻找隐藏状态最有可能序列的动态规划算法,这种序列被称为维特比路径,其结果是一系列可以观察到的事件,特别是在隐藏的Markov模型中。
B. 程序员算法是干什么的
算法,从字面意义上解释,就是用于计算的方法,通过该这种方法可以达到预期的计算结果。目前,被广泛认可的算法专业定义是:算法是模型分析的一组可行的,确定的,有穷的规则。通俗的说,算法也可以理解为一个解题步骤,有一些基本运算和规定的顺序构成。但是从计算机程序设计的角度看,算法由一系列求解问题的指令构成,能根据规范的输入,在有限的时间内获得有效的输出结果。算法代表了用系统的方法来描述解决问题的一种策略机制。
完成同一件事的不同的算法完成的时间和占用的资源可能并不相同,这就牵扯到效率的问题。算法的基本任务是针对一个具体的问题,找到一个高效的处理方法,从而完成任务。
C. 作为程序员,你们都学过哪些印象深刻的算法
如果你是一个有追求的程序员,不甘心满足天天在小公司待着,而是想去BAT或者TMD这种大型公司或者超级独角兽公司的话,那算法是绝对绕不开的一个话题。就拿本人还有周围去面试过大公司的朋友来举例子。BAT面试全都要涉及到算法。腾讯我去面试过,在二面挂了,一面和二面其实都有算法题目,一面相对而言简单一些,二面的算法就有难度了。而我有一个朋友,拿到了腾讯和阿里的offer,他回来说腾讯五轮面试中有一轮面试是专门考察算法,总共六道算法题目给了你两个小时时间作答。阿里的电话面试里面也有一轮视频面试专门考察算法,也是当着他们的面手写算法。光讲思路在腾讯行不通的。本人曾面对腾讯的题目跟面试官说我谈谈思路吧,面试官直接怼回来说不要谈什么思路,直接写出来给我看,平时怎么敲代码现在就怎么写出来。可见对待算法完全没有任何商量的余地。至于头条公司那就更是如此了,因为头条就是一家以算法驱动的公司,对算法要求也比较高。但是即便如此,BAT对待算法还远达不到称之为精通的地步。
D. 作为一个程序员,有哪些常用的算法
常用的算法有:递推法、贪心法、列举法、递归法、分治法和模拟法
原则:1. 扎实的基础。数据结构、离散数学、编译原理,这些是所有计算机科学的基础,如果不掌握他们,很难写出高水平的程序。据我的观察,学计算机专业的人比学其他专业的人更能写出高质量的软件。程序人人都会写,但当你发现写到一定程度很难再提高的时候,就应该想想是不是要回过头来学学这些最基本的理论。不要一开始就去学OOP,即使你再精通OOP,遇到一些基本算法的时候可能也会束手无策。
2. 丰富的想象力。不要拘泥于固定的思维方式,遇到问题的时候要多想几种解决问题的方案,试试别人从没想过的方法。丰富的想象力是建立在丰富的知识的基础上,除计算机以外,多涉猎其他的学科,比如天文、物理、数学等等。另外,多看科幻电影也是一个很好的途径。
3. 最简单的是最好的。这也许是所有科学都遵循的一条准则,如此复杂的质能互换原理在爱因斯坦眼里不过是一个简单得不能再简单的公式:E=mc2。简单的方法更容易被人理解,更容易实现,也更容易维护。遇到问题时要优先考虑最简单的方案,只有简单方案不能满足要求时再考虑复杂的方案。
4. 不钻牛角尖。当你遇到障碍的时候,不妨暂时远离电脑,看看窗外的风景,听听轻音乐,和朋友聊聊天。当我遇到难题的时候会去玩游戏,而且是那种极暴力的打斗类游戏,当负责游戏的那部分大脑细胞极度亢奋的时候,负责编程的那部分大脑细胞就得到了充分的休息。当重新开始工作的时候,我会发现那些难题现在竟然可以迎刃而解。
5. 对答案的渴求。人类自然科学的发展史就是一个渴求得到答案的过程,即使只能知道答案的一小部分也值得我们去付出。只要你坚定信念,一定要找到问题的答案,你才会付出精力去探索,即使最后没有得到答案,在过程中你也会学到很多东西。
6. 多与别人交流。三人行必有我师,也许在一次和别人不经意的谈话中,就可以迸出灵感的火花。多上上网,看看别人对同一问题的看法,会给你很大的启发。
7. 良好的编程风格。注意养成良好的习惯,代码的缩进编排,变量的命名规则要始终保持一致。大家都知道如何排除代码中错误,却往往忽视了对注释的排错。注释是程序的一个重要组成部分,它可以使你的代码更容易理解,而如果代码已经清楚地表达了你的思想,就不必再加注释了,如果注释和代码不一致,那就更加糟糕。
8. 韧性和毅力。这也许是"高手"和一般程序员最大的区别。A good programming is 99 weat and 1 ffee。高手们并不是天才,他们是在无数个日日夜夜中磨练出来的。成功能给我们带来无比的喜悦,但过程却是无比的枯燥乏味。你不妨做个测试,找个10000以内的素数表,把它们全都抄下来,然后再检查三遍,如果能够不间断地完成这一工作,你就可以满足这一条。
希望对你有帮助
E. 如果程序员说:让我看看你的算法,是什么意思
他是想了解你是用什么方法(什么途径)求解的。
算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。如果一个算法有缺陷,或不适合于某个问题,执行这个算法将不会解决这个问题。不同的算法可能用不同的时间、空间或效率来完成同样的任务。一个算法的优劣可以用空间复杂度与时间复杂度来衡量。
算法中的指令描述的是一个计算,当其运行时能从一个初始状态和(可能为空的)初始输入开始,经过一系列有限而清晰定义的状态,最终产生输出并停止于一个终态。
同一问题可用不同算法解决,而一个算法的质量优劣将影响到算法乃至程序的效率。算法分析的目的在于选择合适算法和改进算法。一个算法的评价主要从时间复杂度和空间复杂度来考虑。
时间复杂度
算法的时间复杂度是指执行算法所需要的计算工作量。一般来说,计算机算法是问题规模n 的函数f(n),算法的时间复杂度也因此记做。
T(n)=Ο(f(n))
因此,问题的规模n 越大,算法执行的时间的增长率与f(n) 的增长率正相关,称作渐进时间复杂度(Asymptotic Time Complexity)。
空间复杂度
算法的空间复杂度是指算法需要消耗的内存空间。其计算和表示方法与时间复杂度类似,一般都用复杂度的渐近性来表示。同时间复杂度相比,空间复杂度的分析要简单得多。
正确性
算法的正确性是评价一个算法优劣的最重要的标准。
可读性
算法的可读性是指一个算法可供人们阅读的容易程度。 [1]
健壮性
健壮性是指一个算法对不合理数据输入的反应能力和处理能力,也称为容错性。
F. 算法不扎实的程序员,每一个都很慌
初学者经常问这样的问题,然而这些其实是错误的问题。
对于初学者而言,你最应该优先考虑的是,哪些东西构成了程序的基础?
最经典的一句话: 程序 = 数据结构 + 算法 。
如果说编程语言是程序的血肉,那么算法就是程序的灵魂。
人不能没有血肉之躯,但是没有灵魂的人依然只是一个死人。
不能单纯依靠算法衡量一个程序员的好坏,但是面试的时候考算法绝对是简单高效的筛选手段。近些年大厂的面试几乎必考算法也是这个原因。每一个算法学的不扎实的程序员,在面试的时候都很慌。
下面这些书籍应该是算法方面最常见的经典书籍。我有幸都读过,有些读完了,有些半途而废,不过基本上也都算是熟悉。顺序上由易到难,从薄到厚,每本书下面我会简单的介绍一番,希望能对你的学习有所帮助。
首先是两本算法入门书籍,也可以当做算法读物:
《啊哈!算法》
用他的自我介绍的来讲:“这不过是一本有趣的算法书而已,和别的算法书比较,如果硬要说它有什么特点的话,那就是你能看懂它。”
图文并茂,而且画风有趣,适合新手入门,但是代码是C的,看着比较累,文字也略显冗长。
图是非常棒的,启蒙用,非教科书
《算法图解》
和《啊哈》类似,他的介绍是:“像小说一样有趣的算法入门书。”
书里面讲的很好,python代码也很容易读懂,比之《啊哈!算法》,书中的例子没有那么有趣,但是图很清晰,文字和代码不冗杂。
缺点同样是非教科书,非常浅显,三四个小时就看完了。有一种刚刚热身的感觉。
接下来这几本都是最常见的书了:
《数据结构与算法分析C语言描述》
这本书的作者几乎不浪费笔墨在一些简单的地方。书很薄,但是覆盖面很广很深,作者实在是非常厉害。
不过反过来说,就是有些地方讲的语焉不详……
这本书还有java语言版本的,但是相比之下C的更好一些。
挺好的一本书。
还有一点是翻译不是很给力,好多人都没坚持看完。
《数据结构与算法Python语言实现》
英文版评分非常高,中文版评分非常低……
据说是也翻译的不好。另外就是本书自身错误也不少……几版过后依然很多没有改过来。
书中数学证明和介绍比较简单。因为采用Python语言的原因,比较易读。
浅显易懂,内容上循序渐进,环环相扣。相比于上一本,我会更推荐一些。厚度也不算厚。
《数据结构与算法 Python语言描述》
北大教授裘宗燕的书,这本书前面写的挺好的,尤其是在面向对象还有ADT等思想的阐述,都很不错。
但是读到后来给我一种虎头蛇尾的感觉,前面气势如虹绪论就写了很长,最后三章感觉有点草草收尾的意思。就像编辑在催稿,而作者很忙的样子……
另外就是这本书的编排顺序我个人也不是特别喜欢。
接下来是两本大部头,都是非常厚的书。
他们最大的特点就是:出现率远大于看完率
《算法导论》
算法书中的权威,MIT的6.046J就是按照这个来讲的。
公认最好的算法书,组织结构合理,内容详尽。引导读者从思维方式上对算法进行领悟。
书中对算法的数学结构进行了详尽的阐述。有非常多的数学证明。
这本书我说不出什么缺点,只能说有些内容是因为我还没到大牛的境界,暂时还无法体会理解。
我个人的观点是:不要纠结于详细的伪代码,不用纠结于连篇累牍的讲解。体会其中算法的精髓就好。
《算法》第四版
如果说,《算法导论》是学术上最好书,那这本应该是实际应用最好的书。
它对数学的要求比《算法导论》低很多,摒弃了算法的证明。
书中具体给出了每位程序员应知应会的50个算法,深入浅出,大量图解。非常棒。
java基础的话你能撸出来Hello World基本上就可以开始看这本书了,这本书最大的不友好之处在于它的第一章非常长,没看过的人又不知道哪里可以跳过。
这本书后面的翻译感觉不如前边了,不知道是换人了还是DDL了……
翻开书就会看到很多的图,配套作者在coursera上面的课程学的话事半功倍!
接下来的几本我看的比较少,简单介绍一下,希望大家自己去发现和了解,不要漏下这些好书:
《编程珠玑》
很薄一本啊,但是我放在那还没看完……
这本书被称为: 历史 上最伟大的计算机科学着作之一
融深邃思想、实战技术与趣味轶事于一炉的奇书。
内容不深,但是不是一个知识点一个知识点的给你讲解算法原理的。
这本书的核心思想是让你了解如何正确选择和高效地实现算法。书中还有一些趣闻轶事,看着倒是很有意思~
有兴趣的同学可以看看~
《算法竞赛入门经典》系列
算法竞赛入门经典书,ACM必备书籍吧算是。书中题目对于竞赛来说比较简单,但是对于一般我们平时工程来说偏难。语言用的是C/C++,请好好做例题好好做作业,读书的时候好好思考和复习~
反正我是没读过,捂脸……
《剑指Offer》
这个书很有意思,对于在校生来说我个人觉得是必看的书。没有任何工作经验的同学在面试的时候真的会被问懵的。这本书可以让你了解如何应付考官日常问题,在解答面试问题的时候,书中很多方法和思路会让考官觉得你思考的很全面,给你加不少分。
我面试的时候也曾快速扫过一遍这本书,让我在回答问题的时候条理更清晰。书中代码是C的,emmm,于是代码部分我就没太看……
《用Python解决数据结构与算法问题》
最后给大家推荐一本在线的 免费 的算法书。
https://facert.gitbooks.io/python-data-structure-cn/
不是大部头,也不是读物,新手入门足够用,书中介绍了大多数日常需要的算法,并且讲的比较浅显~转行的新手基本可以通过这本书来快速掌握常用基本算法了~
反正免费,是否适合自己看两页也就get了~
如果需要PDF版,可以在“程序员必修课”公众号后台回复:“Python算法书”获取。
G. 作为程序员提高编程能力的几个基础算法
一:快速排序算法
快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序n个项目要Ο(nlogn)次比较。在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他Ο(nlogn)算法更快,因为它的内部循环(innerloop)可以在大部分的架构上很有效率地被实现出来。
快速排序使用分治法(Divideandconquer)策略来把一个串行(list)分为两个子串行(sub-lists)。
算法步骤:
1从数列中挑出一个元素,称为“基准”(pivot),
2重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
3递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会退出,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
二:堆排序算法
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
堆排序的平均时间复杂度为Ο(nlogn) 。
创建一个堆H[0..n-1]
把堆首(最大值)和堆尾互换
3.把堆的尺寸缩小1,并调用shift_down(0),目的是把新的数组顶端数据调整到相应位置
4.重复步骤2,直到堆的尺寸为1
三:归并排序
归并排序(Mergesort,台湾译作:合并排序)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(DivideandConquer)的一个非常典型的应用。
1.申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
2.设定两个指针,最初位置分别为两个已经排序序列的起始位置
3.比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
4.重复步骤3直到某一指针达到序列尾
5.将另一序列剩下的所有元素直接复制到合并序列尾
四:二分查找算法
二分查找算法是一种在有序数组中查找某一特定元素的搜索算法。搜素过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜素过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。折半搜索每次把搜索区域减少一半,时间复杂度为Ο(logn) 。
五:BFPRT(线性查找算法)
BFPRT算法解决的问题十分经典,即从某n个元素的序列中选出第k大(第k小)的元素,通过巧妙的分析,BFPRT可以保证在最坏情况下仍为线性时间复杂度。该算法的思想与快速排序思想相似,当然,为使得算法在最坏情况下,依然能达到o(n)的时间复杂度,五位算法作者做了精妙的处理。
1.将n个元素每5个一组,分成n/5(上界)组。
2.取出每一组的中位数,任意排序方法,比如插入排序。
3.递归的调用selection算法查找上一步中所有中位数的中位数,设为x,偶数个中位数的情况下设定为选取中间小的一个。
4.用x来分割数组,设小于等于x的个数为k,大于x的个数即为n-k。
5.若i==k,返回x;若i<k,在小于x的元素中递归查找第i小的元素;若i>k,在大于x的元素中递归查找第i-k小的元素。
终止条件:n=1时,返回的即是i小元素。
六:DFS(深度优先搜索)
深度优先搜索算法(Depth-First-Search),是搜索算法的一种。它沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所有边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。DFS属于盲目搜索。
深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用拓扑排序表可以方便的解决很多相关的图论问题,如最大路径问题等等。一般用堆数据结构来辅助实现DFS算法。
深度优先遍历图算法步骤:
1.访问顶点v;
2.依次从v的未被访问的邻接点出发,对图进行深度优先遍历;直至图中和v有路径相通的顶点都被访问;
3.若此时图中尚有顶点未被访问,则从一个未被访问的顶点出发,重新进行深度优先遍历,直到图中所有顶点均被访问过为止。
上述描述可能比较抽象,举个实例:
DFS在访问图中某一起始顶点v后,由v出发,访问它的任一邻接顶点w1;再从w1出发,访问与w1邻接但还没有访问过的顶点w2;然后再从w2出发,进行类似的访问,…如此进行下去,直至到达所有的邻接顶点都被访问过的顶点u为止。
接着,退回一步,退到前一次刚访问过的顶点,看是否还有其它没有被访问的邻接顶点。如果有,则访问此顶点,之后再从此顶点出发,进行与前述类似的访问;如果没有,就再退回一步进行搜索。重复上述过程,直到连通图中所有顶点都被访问过为止。
七:BFS(广度优先搜索)
广度优先搜索算法(Breadth-First-Search),是一种图形搜索算法。简单的说,BFS是从根节点开始,沿着树(图)的宽度遍历树(图)的节点。如果所有节点均被访问,则算法中止。
BFS同样属于盲目搜索。一般用队列数据结构来辅助实现BFS算法。
1.首先将根节点放入队列中。
2.从队列中取出第一个节点,并检验它是否为目标。
如果找到目标,则结束搜寻并回传结果。
否则将它所有尚未检验过的直接子节点加入队列中。
3.若队列为空,表示整张图都检查过了——亦即图中没有欲搜寻的目标。结束搜寻并回传“找不到目标”。
4.重复步骤2。
八:Dijkstra算法
戴克斯特拉算法(Dijkstra’salgorithm)是由荷兰计算机科学家艾兹赫尔·戴克斯特拉提出。迪科斯彻算法使用了广度优先搜索解决非负权有向图的单源最短路径问题,算法最终得到一个最短路径树。该算法常用于路由算法或者作为其他图算法的一个子模块。
该算法的输入包含了一个有权重的有向图G,以及G中的一个来源顶点S。我们以V表示G中所有顶点的集合。每一个图中的边,都是两个顶点所形成的有序元素对。(u,v)表示从顶点u到v有路径相连。我们以E表示G中所有边的集合,而边的权重则由权重函数w:E→[0,∞]定义。因此,w(u,v)就是从顶点u到顶点v的非负权重(weight)。边的权重可以想象成两个顶点之间的距离。任两点间路径的权重,就是该路径上所有边的权重总和。已知有V中有顶点s及t,Dijkstra算法可以找到s到t的最低权重路径(例如,最短路径)。这个算法也可以在一个图中,找到从一个顶点s到任何其他顶点的最短路径。对于不含负权的有向图,Dijkstra算法是目前已知的最快的单源最短路径算法。
1.初始时令S=,T=,T中顶点对应的距离值
若存在<V0,Vi>,d(V0,Vi)为<V0,Vi>弧上的权值
若不存在<V0,Vi>,d(V0,Vi)为∞
2.从T中选取一个其距离值为最小的顶点W且不在S中,加入S
3.对其余T中顶点的距离值进行修改:若加进W作中间顶点,从V0到Vi的距离值缩短,则修改此距离值
重复上述步骤2、3,直到S中包含所有顶点,即W=Vi为止
九:动态规划算法
动态规划(Dynamicprogramming)是一种在数学、计算机科学和经济学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。
动态规划背后的基本思想非常简单。大致上,若要解一个给定问题,我们需要解其不同部分(即子问题),再合并子问题的解以得出原问题的解。通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量:一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个子问题解之时直接查表。这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用。
关于动态规划最经典的问题当属背包问题。
1.最优子结构性质。如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质(即满足最优化原理)。最优子结构性质为动态规划算法解决问题提供了重要线索。
2.子问题重叠性质。子问题重叠性质是指在用递归算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算结果保存在一个表格中,当再次需要计算已经计算过的子问题时,只是在表格中简单地查看一下结果,从而获得较高的效率。
十:朴素贝叶斯分类算法
朴素贝叶斯分类算法是一种基于贝叶斯定理的简单概率分类算法。贝叶斯分类的基础是概率推理,就是在各种条件的存在不确定,仅知其出现概率的情况下,如何完成推理和决策任务。概率推理是与确定性推理相对应的。而朴素贝叶斯分类器是基于独立假设的,即假设样本每个特征与其他特征都不相关。
朴素贝叶斯分类器依靠精确的自然概率模型,在有监督学习的样本集中能获取得非常好的分类效果。在许多实际应用中,朴素贝叶斯模型参数估计使用最大似然估计方法,换言朴素贝叶斯模型能工作并没有用到贝叶斯概率或者任何贝叶斯模型。
尽管是带着这些朴素思想和过于简单化的假设,但朴素贝叶斯分类器在很多复杂的现实情形中仍能够取得相当好的效果。
通过掌握以上算法,能够帮你迅速提高编程能力,成为一名优秀的程序员。
H. 程序员必须掌握哪些算法
一.基本算法:
枚举. (poj1753,poj2965)
贪心(poj1328,poj2109,poj2586)
递归和分治法.
递推.
构造法.(poj3295)
模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996)
二.图算法:
图的深度优先遍历和广度优先遍历.
最短路径算法(dijkstra,bellman-ford,floyd,heap+dijkstra)
(poj1860,poj3259,poj1062,poj2253,poj1125,poj2240)
最小生成树算法(prim,kruskal)
(poj1789,poj2485,poj1258,poj3026)
拓扑排序 (poj1094)
二分图的最大匹配 (匈牙利算法) (poj3041,poj3020)
最大流的增广路算法(KM算法). (poj1459,poj3436)
三.数据结构.
串 (poj1035,poj3080,poj1936)
排序(快排、归并排(与逆序数有关)、堆排) (poj2388,poj2299)
简单并查集的应用.
哈希表和二分查找等高效查找法(数的Hash,串的Hash)
(poj3349,poj3274,POJ2151,poj1840,poj2002,poj2503)
哈夫曼树(poj3253)
堆
trie树(静态建树、动态建树) (poj2513)
四.简单搜索
深度优先搜索 (poj2488,poj3083,poj3009,poj1321,poj2251)
广度优先搜索(poj3278,poj1426,poj3126,poj3087.poj3414)
简单搜索技巧和剪枝(poj2531,poj1416,poj2676,1129)
五.动态规划
背包问题. (poj1837,poj1276)
型如下表的简单DP(可参考lrj的书 page149):
E[j]=opt{D+w(i,j)} (poj3267,poj1836,poj1260,poj2533)
E[i,j]=opt{D[i-1,j]+xi,D[i,j-1]+yj,D[i-1][j-1]+zij} (最长公共子序列) (poj3176,poj1080,poj1159)
C[i,j]=w[i,j]+opt{C[i,k-1]+C[k,j]}.(最优二分检索树问题)
六.数学
组合数学:
1.加法原理和乘法原理.
2.排列组合.
3.递推关系.
(POJ3252,poj1850,poj1019,poj1942)
数论.
1.素数与整除问题
2.进制位.
3.同余模运算.
(poj2635, poj3292,poj1845,poj2115)
计算方法.
1.二分法求解单调函数相关知识.(poj3273,poj3258,poj1905,poj3122)
七.计算几何学.
几何公式.
叉积和点积的运用(如线段相交的判定,点到线段的距离等). (poj2031,poj1039)
多边型的简单算法(求面积)和相关判定(点在多边型内,多边型是否相交)
(poj1408,poj1584)
凸包. (poj2187,poj1113)
中级(校赛压轴及省赛中等难度):
一.基本算法:
C++的标准模版库的应用. (poj3096,poj3007)
较为复杂的模拟题的训练(poj3393,poj1472,poj3371,poj1027,poj2706)
二.图算法:
差分约束系统的建立和求解. (poj1201,poj2983)
最小费用最大流(poj2516,poj2516,poj2195)
双连通分量(poj2942)
强连通分支及其缩点.(poj2186)
图的割边和割点(poj3352)
最小割模型、网络流规约(poj3308)
三.数据结构.
线段树. (poj2528,poj2828,poj2777,poj2886,poj2750)
静态二叉检索树. (poj2482,poj2352)
树状树组(poj1195,poj3321)
RMQ. (poj3264,poj3368)
并查集的高级应用. (poj1703,2492)
KMP算法. (poj1961,poj2406)
四.搜索
最优化剪枝和可行性剪枝
搜索的技巧和优化 (poj3411,poj1724)
记忆化搜索(poj3373,poj1691)
五.动态规划
较为复杂的动态规划(如动态规划解特别的旅行商TSP问题等)
(poj1191,poj1054,poj3280,poj2029,poj2948,poj1925,poj3034)
记录状态的动态规划. (POJ3254,poj2411,poj1185)
树型动态规划(poj2057,poj1947,poj2486,poj3140)
六.数学
组合数学:
1.容斥原理.
2.抽屉原理.
3.置换群与Polya定理(poj1286,poj2409,poj3270,poj1026).
4.递推关系和母函数.
数学.
1.高斯消元法(poj2947,poj1487, poj2065,poj1166,poj1222)
2.概率问题. (poj3071,poj3440)
3.GCD、扩展的欧几里德(中国剩余定理) (poj3101)
计算方法.
1.0/1分数规划. (poj2976)
2.三分法求解单峰(单谷)的极值.
3.矩阵法(poj3150,poj3422,poj3070)
4.迭代逼近(poj3301)
随机化算法(poj3318,poj2454)
杂题(poj1870,poj3296,poj3286,poj1095)
七.计算几何学.
坐标离散化.
扫描线算法(例如求矩形的面积和周长并,常和线段树或堆一起使用)
(poj1765,poj1177,poj1151,poj3277,poj2280,poj3004)
多边形的内核(半平面交)(poj3130,poj3335)
几何工具的综合应用.(poj1819,poj1066,poj2043,poj3227,poj2165,poj3429)
高级(regional中等难度):
一.基本算法要求:
代码快速写成,精简但不失风格
(poj2525,poj1684,poj1421,poj1048,poj2050,poj3306)
保证正确性和高效性. poj3434
二.图算法:
度限制最小生成树和第K最短路. (poj1639)
最短路,最小生成树,二分图,最大流问题的相关理论(主要是模型建立和求解)
(poj3155, poj2112,poj1966,poj3281,poj1087,poj2289,poj3216,poj2446
最优比率生成树. (poj2728)
最小树形图(poj3164)
次小生成树.
无向图、有向图的最小环
三.数据结构.
trie图的建立和应用. (poj2778)
LCA和RMQ问题(LCA(最近公共祖先问题) 有离线算法(并查集+dfs) 和 在线算法(RMQ+dfs)).(poj1330)
双端队列和它的应用(维护一个单调的队列,常常在动态规划中起到优化状态转移的目的). (poj2823)
左偏树(可合并堆).
后缀树(非常有用的数据结构,也是赛区考题的热点).(poj3415,poj3294)
四.搜索
较麻烦的搜索题目训练(poj1069,poj3322,poj1475,poj1924,poj2049,poj3426)
广搜的状态优化:利用M进制数存储状态、转化为串用hash表判重、按位压缩存储状态、双向广搜、A*算法. (poj1768,poj1184,poj1872,poj1324,poj2046,poj1482)
深搜的优化:尽量用位运算、一定要加剪枝、函数参数尽可能少、层数不易过大、可以考虑双向搜索或者是轮换搜索、IDA*算法. (poj3131,poj2870,poj2286)
五.动态规划
需要用数据结构优化的动态规划.(poj2754,poj3378,poj3017)
四边形不等式理论.
较难的状态DP(poj3133)
六.数学
组合数学.
1.MoBius反演(poj2888,poj2154)
2.偏序关系理论.
博奕论.
1.极大极小过程(poj3317,poj1085)
2.Nim问题.
七.计算几何学.
半平面求交(poj3384,poj2540)
可视图的建立(poj2966)
点集最小圆覆盖.
对踵点(poj2079)
I. 作为一个程序员,还有比“弟高值”更丧心病狂的算法吗
程序员的世界变态,但跳出程序员的数字世界,发现这个世界更变态。
J. 程序员开发用到的十大基本算法
算法一:快速排序算法
快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。
快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。
算法步骤:
1 从数列中挑出一个元素,称为 “基准”(pivot),
2 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
3 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会退出,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
算法二:堆排序算法
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序的平均时间复杂度为Ο(nlogn) 。
算法步骤:
1.创建一个堆H[0..n-1]
2.把堆首(最大值)和堆尾互换
3.把堆的尺寸缩小1,并调用shift_down(0),目的是把新的数组顶端数据调整到相应位置
4.重复步骤2,直到堆的尺寸为1
算法三:归并排序
归并排序(Merge sort,台湾译作:合并排序)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
算法步骤:
算法四:二分查找算法
二分查找算法是一种在有序数组中查找某一特定元素的搜索算法。搜素过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜 素过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组 为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。折半搜索每次把搜索区域减少一半,时间复杂度为Ο(logn) 。
算法五:BFPRT(线性查找算法)
BFPRT算法解决的问题十分经典,即从某n个元素的序列中选出第k大(第k小)的元素,通过巧妙的分 析,BFPRT可以保证在最坏情况下仍为线性时间复杂度。该算法的思想与快速排序思想相似,当然,为使得算法在最坏情况下,依然能达到o(n)的时间复杂 度,五位算法作者做了精妙的处理。
算法步骤:
终止条件:n=1时,返回的即是i小元素。
算法六:DFS(深度优先搜索)
深度优先搜索算法(Depth-First-Search),是搜索算法的一种。它沿着树的深度遍历树的节点,尽可能深的搜索树的分 支。当节点v的所有边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发 现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。DFS属于盲目搜索。
深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用拓扑排序表可以方便的解决很多相关的图论问题,如最大路径问题等等。一般用堆数据结构来辅助实现DFS算法。
算法步骤:
上述描述可能比较抽象,举个实例:
DFS 在访问图中某一起始顶点 v 后,由 v 出发,访问它的任一邻接顶点 w1;再从 w1 出发,访问与 w1邻 接但还没有访问过的顶点 w2;然后再从 w2 出发,进行类似的访问,… 如此进行下去,直至到达所有的邻接顶点都被访问过的顶点 u 为止。
接着,退回一步,退到前一次刚访问过的顶点,看是否还有其它没有被访问的邻接顶点。如果有,则访问此顶点,之后再从此顶点出发,进行与前述类似的访问;如果没有,就再退回一步进行搜索。重复上述过程,直到连通图中所有顶点都被访问过为止。
算法七:BFS(广度优先搜索)
广度优先搜索算法(Breadth-First-Search),是一种图形搜索算法。简单的说,BFS是从根节点开始,沿着树(图)的宽度遍历树(图)的节点。如果所有节点均被访问,则算法中止。BFS同样属于盲目搜索。一般用队列数据结构来辅助实现BFS算法。
算法步骤:
算法八:Dijkstra算法
戴克斯特拉算法(Dijkstra’s algorithm)是由荷兰计算机科学家艾兹赫尔·戴克斯特拉提出。迪科斯彻算法使用了广度优先搜索解决非负权有向图的单源最短路径问题,算法最终得到一个最短路径树。该算法常用于路由算法或者作为其他图算法的一个子模块。
该算法的输入包含了一个有权重的有向图 G,以及G中的一个来源顶点 S。我们以 V 表示 G 中所有顶点的集合。每一个图中的边,都是两个顶点所形成的有序元素对。(u, v) 表示从顶点 u 到 v 有路径相连。我们以 E 表示G中所有边的集合,而边的权重则由权重函数 w: E → [0, ∞] 定义。因此,w(u, v) 就是从顶点 u 到顶点 v 的非负权重(weight)。边的权重可以想象成两个顶点之间的距离。任两点间路径的权重,就是该路径上所有边的权重总和。已知有 V 中有顶点 s 及 t,Dijkstra 算法可以找到 s 到 t的最低权重路径(例如,最短路径)。这个算法也可以在一个图中,找到从一个顶点 s 到任何其他顶点的最短路径。对于不含负权的有向图,Dijkstra算法是目前已知的最快的单源最短路径算法。
算法步骤:
重复上述步骤2、3,直到S中包含所有顶点,即W=Vi为止
算法九:动态规划算法
动态规划(Dynamic programming)是一种在数学、计算机科学和经济学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。 动态规划常常适用于有重叠子问题和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。
动态规划背后的基本思想非常简单。大致上,若要解一个给定问题,我们需要解其不同部分(即子问题),再合并子问题的解以得出原问题的解。 通常许多 子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量: 一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个 子问题解之时直接查表。 这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用。
关于动态规划最经典的问题当属背包问题。
算法步骤:
算法十:朴素贝叶斯分类算法
朴素贝叶斯分类算法是一种基于贝叶斯定理的简单概率分类算法。贝叶斯分类的基础是概率推理,就是在各种条件的存在不确定,仅知其出现概率的情况下, 如何完成推理和决策任务。概率推理是与确定性推理相对应的。而朴素贝叶斯分类器是基于独立假设的,即假设样本每个特征与其他特征都不相关。
朴素贝叶斯分类器依靠精确的自然概率模型,在有监督学习的样本集中能获取得非常好的分类效果。在许多实际应用中,朴素贝叶斯模型参数估计使用最大似然估计方法,换言之朴素贝叶斯模型能工作并没有用到贝叶斯概率或者任何贝叶斯模型。
尽管是带着这些朴素思想和过于简单化的假设,但朴素贝叶斯分类器在很多复杂的现实情形中仍能够取得相当好的效果。