算法的魅力—从二分查找和最长公共子序列说起
Posted Python那些事
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法的魅力—从二分查找和最长公共子序列说起相关的知识,希望对你有一定的参考价值。
有句话说的好,算法是程序的灵魂。是的,在做开发时,尤其是代码重构或者架构设计时,算法是必不可少的内容。最近读了两本算法书,内容非常不错,推荐给大家。一本是《算法图解》,用讲故事的方式展示算法的魅力:
另外一本是《高效算法》,能够让你更全面的了解数据结构和算法:
两本书的代码大部分是基于Python语言的,这里分别从两本书中摘录一部分给大家,可以让大家感受一下算法的魅力。
二分查找
又假设要在字典中找一个以O打头的单词,你也将从中间附近开始。
现在假设你登录Facebook。当你这样做时,Facebook必须核实你是否有其网站的账户,因此必须在其数据库中查找你的用户名。如果你的用户名为karlmageddon,Facebook可从以A打头的部分开始查找,但更合乎逻辑的做法是从中间开始查找。
这是一个查找问题,在前述所有情况下,都可使用同一种算法来解决问题,这种算法就是二分查找。
下面的示例说明了二分查找的工作原理。我随便想一个1~100的数字。
一种糟糕的猜数
这是简单查找,更准确的说法是傻找。每次猜测都只能排除一个数字。如果我想的数字是99,你得猜99次才能猜到!
更佳的查找方式
下面是一种更佳的猜法。从 50开始。
小了,但排除了一半的数字!至此,你知道1~50都小了。接下来,你猜75。
大了,那余下的数字又排除了一半!使用二分查找时,你猜测的是中间的数字,从而每次都将余下的数字排除一半。接下来,你猜63(50和75中间的数字)。
这就是二分查找,你学习了第一种算法!每次猜测排除的数字个数如下。
使用二分查找时,每次都排除一半的数字
不管我心里想的是哪个数字,你在7次之内都能猜到,因为每次猜测都将排除很多数字!
假设你要在字典中查找一个单词,而该字典包含240 000个单词,你认为每种查找最多需要多少步?
如果要查找的单词位于字典末尾,使用简单查找将需要240 000步。使用二分查找时,每次排除一半单词,直到最后只剩下一个单词。
因此,使用二分查找只需18步——少多了!一般而言,对于包含n个元素的列表,用二分查找最多需要log2n步,而简单查找最多需要n步。
下面来看看如何编写执行二分查找的Python代码。这里的代码示例使用了数组。如果你不熟悉数组,也不用担心,你只需知道,可将一系列元素存储在一系列相邻的桶(bucket),即数组中。这些桶从0开始编号:第一个桶的位置为#0,第二个桶为#1,第三个桶为#2,以此类推。
函数binary_search接受一个有序数组和一个元素。如果指定的元素包含在数组中,这个函数将返回其位置。你将跟踪要在其中查找的数组部分——开始时为整个数组。
low = 0
high= len(list) - 1
你每次都检查中间的元素。
mid = (low + high) / 2
guess= list[mid]
如果(low+ high)不是偶数,Python自动将mid向下圆整。
如果猜的数字小了,就相应地修改low。
if guess < item:
low = mid +1
如果猜的数字大了,就修改high。完整的代码如下。
你感受到算法的魅力了吗?
最长公共子序列
最长公共子序列(LCS)是一个在一个序列集合中(通常为两个序列)用来查找所有序列中最长子序列的问题。何为子序列? 从字面意思可以拆分为两部分,子和序列。子说明是原先的序列的一部分,而序列说明是顺序的,需要保持顺序一致。比如,对于字符串 python , pytn 则是其子序列,pynt则不是。
何为最长子序列?顾名思义,两个序列的所有子序列中最长的。下面这种解释可能会更好理解。
问题的解法是采用动态规划,相信大家应该比较熟悉。当 n= |x|和 m= |y|时,对于所有 0≤i≤n和 0≤j≤m,我们计算前缀 x1… xi和 y1…yj的最长公共子序列。这就得到一个复杂度为 n·m的子问题。基于 (i-1,j)、(i,j-1)和 (i-1,j-1)在常数时间内得到的解,就能得到 (i,j)的最优解。因此,我们可以在时间 O(nm)内解决问题 (n,m)。
设序列 x1,…,xi和 y1,…,yj的最长公共子序列为 A[i,j]。在 i= 0或 j= 0时,A[i,j]为空。当 xi≠yj时,xi和 xj中的一个肯定不在最优解中,而且 A[i,j]是 A[i-1,j]和 A[i,j-1]中最长的序列 A。当 xi= yj 时,存在一个最优解使得字符相关,而且 A[i,j]等于 A[i-1,j-1]·xi。这里的符号“·”表示字符串拼接。使用 maximum函数可以让最长序列延伸。
具体的Python代码如下:
你感受到算法的奇妙了吗?
以上内容分别摘自《算法图解-像小说一样有趣的算法入门书》和《高效算法-竞赛、应试与提高必修128例》。想了解更多的内容吗?可以识别下面的二维码购买。
《算法图解》
《高效算法》
福利到!
本次拿出 4 本书作为福利赠送给关注【Python那些事】的小伙伴们,特别感谢图灵教育的赞助与支持。
赠书规则:
1、参与Python高考题《》并且第一个答对的同学赠书1本;
3、大家可以在本留言区留言评论自己想要某本书的理由或者是评论某种算法,小编将从留言区选择最受欢迎的2位赠书。
由于留言区数目有限,会筛选放出认真有价值的评论(刷赞无效,并且会永久取消资格,欢迎举报)。截止日期为6月9日 22:00。
(完)
看完本文有收获?请转发分享给更多人
关注「Python那些事」,做全栈开发工程师
以上是关于算法的魅力—从二分查找和最长公共子序列说起的主要内容,如果未能解决你的问题,请参考以下文章