我们在上一次练习今天我们来看一种不同的算法,它可以解决相同的问题;新算法效率更高,但仍然是指数型的,时间复杂度为0(n个2n个/2).

新算法称为在中间相遇算法,将输入列表拆分为大小相等的两部分。前半部分采用与前一练习相同的算法,其中生成所有子集,计算其总和,并将总和与目标进行比较。上半场有可能但不太可能找到目标。如果不是,该算法将生成下半部分的所有子集,并检查每个和,以查看目标和和之间的差异是否是上半部分的和,在这种情况下,已找到所需的子集。

您的任务是实现中间相遇算法以解决子集和问题。完成后,欢迎您阅读运行建议的解决方案,或在下面的评论中发布自己的解决方案或讨论练习。

页:1 2

子集总和

2012年3月27日

子项和问题要求您找到一组整数的子集,这些整数与给定的目标求和;例如,给定集合{267 439 869 961 1000 1153 1246 1598 1766 1922}和目标5842,子集{869 9611 1000 1246 1766}的总和为5842。这是一个众所周知的NP问题,通过动态编程的标准解决方案需要时间O(运行)(n个2n个). 基本思想很简单:生成一个子集列表,计算每个子集的总和,然后将总和返回给目标。

动态编程解决方案具有相同的功能O(运行)(n个2n个)时间复杂性,但分阶段构建解决方案。矩阵具有n个行和2n个柱;行用标记n个输入值,列用各种子项标记,每个单元格包含n个值的最大值为当前行的总和。我们将看一个示例:从{1-342}中找到总和为0的项目子集。考虑列表的第一个元素后,第一行有两列,我们忽略的空列和列1:

  1
1 1

在第二行中,有四列:我们忽略的null列和列-3、1和2:

  -3 1 2
1   1  
-3 -3 1 -3 1

当我们添加第三行时,有八列:我们忽略的空列,六列-3、-2、1、2、4和5,以及1的隐藏列,可以用两种不同的方式形成,即1本身和-3和4的总和:

  -3 -2 1 2 4 5
1     1      
-3 -3 -3 1 1      
4 -3 -3 1 1 -3 1 4 4 1 4

当我们添加第四行时,共有十六列,但表中只出现十一列:-3、-2、-1、0、1、2、3、4、5、6和7。我们忽略了空列,并且有四个隐藏列对应于以下汇总表,表中只显示其中一个(不管是哪一个):1=-3+4、2=-3+1+4、1+2=-3+2+4和4=-3+1+2+4:

  -3 -2 -1 0 1 2 4 5 6 7
1         1            
-3 -3 -第3页     1            
4 -3 -3 1     1 -3 1 4   4 1 4    
2 -3 -3 1 -3 2个 -3 1 2 1 -3 1 4 1 2 4 1 4 2 4 1 2 4

解决方案是子集{-3122}。很抱歉我没有餐桌。

您的任务是编写一个函数来解决子项和问题。完成后,欢迎您阅读运行建议的解决方案,或在下面的评论中发布自己的解决方案或讨论练习。

页:1 2

Base-26算术

2012年3月23日

一位名叫Prashant的读者最近写了一封信,建议使用基于26的算术:

编写一个函数,该函数采用两个以26为基数的数字,其中数字由字母a=0、B=1、…Z=25表示,并使用相同的符号返回其乘积。例如,CSGHJ×CBA=FNEUZJA。

Prashant担心这个问题是C/C++特有的,但这不是问题。

你的任务是编写基数为26的乘法函数。完成后,欢迎您阅读运行建议的解决方案,或在下面的评论中发布自己的解决方案或讨论练习。

页:1 2

因子分解多个RSA密钥

2012年3月20日

2月15日《纽约时报》 出版描述了攻击Arjen Lenstra等人的RSA密钥生成算法;纳迪娅·亨宁格和她的朋友同样的研究,但尚未发表他们的研究成果次数错过了Lenstra论文的精髓,并报告说,千分之二的网络密码是不安全的,这是不正确的;丹·卡明斯基给出了一个更好的描述并解释了为什么不用担心。

问题不在于RSA算法本身,而在于生成RSA算法使用的密钥。我们在前面的练习中研究了密钥生成算法。简单地说,密钥生成算法选择两个大素数,通常称为第页q个,并使用它们创建公钥和私钥;公钥是第页q个RSA算法的安全性依赖于这样一个事实,即很难将公钥分解为其两个组件第页q个但是,如果您这样做,很容易确定相应的私钥,任何这样做的人都可以解密任何这样编码的消息。

Lenstra/Henninger发现,由于密钥生成算法的某些实现中存在缺陷,多个私钥使用了相同的p。以下是Lenstra/Henninger和他们的同事所做的:首先,他们使用扫描器; 两支球队都收集了大约1200万把钥匙。然后,他们计算每个密钥与其他密钥配对的gcd;当gcd不为1时,它是密钥的一个因素,另一个因素很容易通过除法找到,并且可以从这两个因素中确定私钥。

今天的练习要求您重新创建Lenstra/Heninger用来寻找因子的计算。我们将使用这组21个公钥;这些键很小,很容易分解,但真正的键要大得多:

708894553 704488409 705674273
707478271 710167019 708093251
702013379 704030867 708691187
708374743 712748719 713581951
704387447 707015741 704308279
710872423 707947453 704996429
706323757 705031051 714623803

我们将使用两种不同的方法来查找可分解键。上面提到的第一种方法是将每个密钥与其他密钥配对并计算gcd。该算法的时间复杂度为O(运行)(n个 2),如果n个=21,但如果n个=12,000,000; 144万亿美元的资金都需要一段时间。第二种算法首先对所有密钥进行乘法运算,然后对每个密钥进行乘法运算k个计算gcd(k个,k个触头(修订版k个 2) /k个). 第二种算法需要时间O(运行)(n个日志n个); 该产品采用线性时间,每个键的gcd采用线性时间并且有一个日志日志的附加因子n个因为密钥乘积上的大整数算法。Lenstra/Heninger实际使用的算法都不是;纸张丹尼尔·伯恩斯坦(Daniel Bernstein)给出了算法,但它比我们今天关心的要复杂得多,而且上述线性算法也不算太差,只要n个不是太大,只要你有一个好的大集成库。

您的任务是编写实现上述两种算法的函数,并使用它们尽可能多地计算键。完成后,欢迎您阅读运行建议的解决方案,或在下面的评论中发布自己的解决方案或讨论练习。

页:1 2

今天的练习来自书本计算机程序的结构和解释作者:Abelson和Sussman(练习1.3):

定义一个过程,该过程接受三个数字作为参数,并返回两个较大数字的平方和。

您的任务是编写指示的函数。完成后,欢迎您阅读运行建议的解决方案,或在下面的评论中发布自己的解决方案或讨论练习。

页:1 2

完全幂谓词

2012年3月13日

一个数字n个如果存在b条e(电子)对于其中b条e(电子)=n个例如216=6= 2· 3是一种完美的力量,但72=2· 32不是。完美幂的测试与其他幂谓词类似我们已经看到了,在某些因子分解算法中很有用。

确定一个数字是否是完美幂的诀窍是要知道,如果这个数字是完美幂,那么指数e(电子)必须小于log2 n个,因为如果e(电子)大于2e(电子)将大于n个此外,只需要测试素数e(电子)s、 因为如果一个数字是一个复合指数的完美幂,那么它也将是复合成分素因子的完美幂;例如,215= 32768 = 32= 85是一个完美的立方根,也是一个完美的五次根。

你的任务是写一个函数来确定一个数字是否是一个完美幂。完成后,欢迎您阅读运行建议的解决方案,或在下面的评论中发布自己的解决方案或讨论练习。

页:1 2

稀疏集

2012年3月9日

今天我们来看一个聪明的数据结构,用于存储范围0上的稀疏整数集。。u个-1,执行初始化、查找和插入是时间O(运行)(1) 和中的迭代O(运行)(n个),其中n个是集合中的元素数。1993年研究了数据结构文章Preston Briggs和Linda Torczon在Jon Bentley的书的练习1.9(第一版中的1.8)中的“稀疏集的有效表示”编程珠玑1974年的练习2.12计算机算法的设计与分析作者:Al-Aho、John Hopcroft和Jeffrey Ullman;数据结构本身可以追溯到计算的民间传说。

数据结构考虑从0到u个−1; 根据具体情况,整数可能会映射到其他东西,但我们不关心这一点。任何给定的集合都包含n个从宇宙中选择的物品;没有重复项。请注意n个u个当然,而且很可能n个远小于u个-否则,您可能会使用位向量来表示集合。还要注意的是,我们正在以牺牲空间为代价优化速度,因为位向量需要u个位,但我们的数据结构需要2u个整数。

考虑一个位向量。设置一个位是一个恒定时间操作,就像检查一个位是否被设置一样。但初始化位向量和迭代位向量的集合元素都需要与位向量大小成比例的时间。我们的稀疏集将迭代时间减少为与集的大小(而不是宇宙的大小)成比例的时间,并将初始化时间减少为常数。

稀疏集由两个向量表示,我们将其称为稠密(缩写为D类)和稀疏(缩写S公司). 最初n个,集合中的元素数为零;这两个向量未初始化,可能包含任何内容。添加元素0≤k个<u个到一个尚未包含k个,我们设置D类[n个]至k个,S公司[k个]至n个,并增加n个乘1,一个花费恒定时间的操作。在此之后,两个向量互相指向,这就对在恒定时间内也有效的集合成员身份进行了测试:一个元素k个在且仅当S公司[k个] <n个D类[S公司[k个]] ==k>注意,如果k个不是集合的成员S公司[k个]无关紧要;要么是S公司[k个]将大于n个或者它将指向D类这并不是指向它。右上方的图表显示了一个包含元素5、1和4的集合;蓝色方框可以包含任何值。要迭代集合的元素,请阅读D类[0 ..n个−1],这需要时间O(运行)(n个),并清除设置使n个=0,这需要时间O(运行)(1); 特别注意,清除集合不需要重新初始化。其他操作,包括size of、delete、union、intersection、difference和set equality都是可能的,并且与位向量相比同样具有时间效率,但我们在此不讨论它们,因为它们很少用于这种集合表示。这些稀疏集的常见用法是编译器中的寄存器分配算法,它们具有固定的范围(机器中的寄存器数),并且在单个处理运行期间频繁更新和清除。

您的任务是实现上述稀疏集的插入、查找、迭代和清除操作。完成后,欢迎您阅读运行建议的解决方案,或在下面的评论中发布自己的解决方案或讨论练习。

页:1 2

联合路由密码

2012年3月6日

美国内战期间,联邦军队部署了历史上最成功的军事密码之一。众所周知,邦联从未破解过密码;事实上,他们甚至开始在报纸上发布截获的信息,希望有人能阅读。该密码是由西联电报公司总负责人安东·斯塔格应俄亥俄州政府的要求设计的;后来,负责俄亥俄州军队的乔治·麦克莱伦将军将密码引入了整个联邦军队。你可以阅读更多关于密码的信息在这里在这里

密码分两个阶段工作。首先,一些具有军事意义的单词被代码词取代;例如,attack可以替换为tulip,短语atdawn可以替换为stripe,因此代码tulip stripe意味着attack at dawn。词典包括人名(林肯,各种将军)、地点(里士满,山顶)、时间(星期二,下午4:30,黎明)和行动(攻击,侦察);一个明文单词可以容纳多个代码词,多个明文词可以编码为一个单词,甚至数字和标点符号也有代码词。该词典的最终版本包括1608个码字。

第二个阶段是路线转位,有许多变体。例如,指定为willow的路由可能会调用六列,其中单词的选择顺序为向下第三列、向上第四列、向下第二列、向下第六列、向上第一列和向下第五列;添加了null来填充最后一行,并在第七列中添加了一个额外的null。

举一个例子:1863年6月1日,林肯总统发来以下电报:

对于COLONEL LUDLOW:
里查森和布朗,特里布内通讯员,
在维克斯堡被捕,在里奇蒙被捕。
请确认他们为什么被剥夺
如果可以的话,把它们拿下来。
林肯。

该词典包括某些代码词:VENUS代表COLONEL,WAYLAND代表CAPTURED,ODOR代表VICKBURG,NEPTUNE代表RICHMOND,ADAM代表LINCOLN。另一个码字NELLY将发送时间指定为4:30PM。因此,信息变为:

对于金星LUDLOW:
里查森和布朗,特里布内通讯员,
气味处的道路在纽顿被封锁。
请确认他们为什么被剥夺
如果可以的话,把它们拿下来。
亚当·奈利

现在,密码管理员选择了一个路径GUARD,该路径按向上第一列、向下第二列、向上第五列、向下第一列和向上第三列的顺序调用五列。他将信息分为五列,最后一行用空填充:

对于金星卢道·理查德森和
部落布朗通讯员
气味处的道路被扣留
在奈普顿请ASCERTAIN为什么
他们被剥夺了权利
如果可以的话,把它们关掉
亚当·奈利(ADAM NELLY)

现在,消息按列路由顺序提取,并在每列后添加空值:

第一列亚当他们在韦兰·布朗亲吻
下栏两位纽顿的金星通讯员关上了NELLY TURNING
第五列up可以得到为什么被剥夺了TRIBUNE和TIMES
在第四栏,理查德森,阿瑟特丹,你填满了贝利
第三列上,如果发现,请闻一下卢森堡专员的气味

然后,按照路线指示器的顺序读取最终信息:

守卫亚当·他们在韦兰·布朗亲吻金星,纽顿的通讯员都关了。内莉·露面能解释为什么会被剥夺审判权,理查德森的案子也会升级,如果你被剥夺了,请闻一闻路德洛专员

解密只是颠倒了这个过程。收件人计算消息中的单词数,绘制适当大小的网格,按路由顺序填写单词,将码字转换为明文等价物,然后阅读消息。

联合路由密码具有强大的优势,它可以处理单词而不是单个字母,这使得抄写和电报中的错误变得不太常见。当然,缺点是必须精心控制代码簿;丢失一本密码本将使敌人能够访问您的所有通信。但这并没有发生,密码在整个战争期间都是安全的。

您的任务是编写一个程序,根据Union路由密码对消息进行加密和解密;为词汇和路线制定自己的约定。完成后,欢迎您阅读运行建议的解决方案,或在下面的评论中发布自己的解决方案或讨论练习。

页:1 2

平衡分隔符

2012年3月2日

这些面试问题令人上瘾;我不得不停下脚步,做点别的。但再加一个也无妨:

编写一个函数,该函数接受字符串并确定字符串中的分隔符是否平衡。分隔符对是()、[]、{}和<>,分隔符可以嵌套。此外,确定字符串分隔符'和“正确匹配;其他分隔符在带引号的字符串中失去了神奇的分隔符属性。如果任何分隔符跟在反斜杠后面,则对其进行转义。

您的任务是编写函数以确定字符串是否具有平衡的分隔符。完成后,欢迎您阅读运行建议的解决方案,或在下面的评论中发布自己的解决方案或讨论练习。

页:1 2