﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-mysileng-随笔分类-JULY_程序员编程艺术</title><link>http://www.cppblog.com/mysileng/category/20208.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 28 May 2013 15:40:05 GMT</lastBuildDate><pubDate>Tue, 28 May 2013 15:40:05 GMT</pubDate><ttl>60</ttl><item><title>程序员编程艺术-----第二十八 ~ 二十九章-----最大连续乘积子串、字符串编辑距离</title><link>http://www.cppblog.com/mysileng/archive/2013/05/28/200661.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Tue, 28 May 2013 14:18:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2013/05/28/200661.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/200661.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2013/05/28/200661.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/200661.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/200661.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;第二十八~二十九章：最大连续乘积子串、字符串编辑距离前言&nbsp; &nbsp; 时间转瞬即逝，一转眼，又有4个多月没来更新blog了，过去4个月都在干啥呢？对的，今2013年元旦和朋友利用业余时间一起搭了个方便朋友们找工作的编程面试算法论坛：为学论坛http://www.51weixu...&nbsp;&nbsp;<a href='http://www.cppblog.com/mysileng/archive/2013/05/28/200661.html'>阅读全文</a><img src ="http://www.cppblog.com/mysileng/aggbug/200661.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2013-05-28 22:18 <a href="http://www.cppblog.com/mysileng/archive/2013/05/28/200661.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序员编程艺术-----第二十七章-----不改变正负数相对顺序重新排列数组</title><link>http://www.cppblog.com/mysileng/archive/2013/05/28/200652.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Tue, 28 May 2013 09:50:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2013/05/28/200652.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/200652.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2013/05/28/200652.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/200652.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/200652.html</trackback:ping><description><![CDATA[<blockquote style="font-family: Arial; font-size: 14.399999618530273px; line-height: 26px; background-color: #ffffff; margin: 0px 0px 0px 40px; padding: 0px; border: currentcolor;"><h3>第二十七章：不改变正负数之间相对顺序重新排列数组.时间O(N)，空间O(1)</h3></blockquote><p style="color: #333333; font-family: Arial; font-size: 14.399999618530273px; line-height: 26px; background-color: #ffffff;"><br /></p><h3>前言</h3><p style="color: #333333; font-family: Arial; font-size: 14.399999618530273px; line-height: 26px; background-color: #ffffff;">&nbsp; &nbsp;&nbsp;在这篇文章：<a href="http://blog.csdn.net/v_july_v/article/details/6803368" target="_blank" style="color: #336699; text-decoration: initial; font-size: 14px;">九月腾讯，创新工场，淘宝等公司最新面试十三题</a>的<span style="font-size: 14px;">第5题(一个未排序整数数组，有正负数，重新排列使负数排在正数前面，并且要求不改变原来的正负数之间相对顺序)，自从去年九月收录了此题至今，一直未曾看到令人满意的答案，为何呢?</span></p><p style="color: #333333; font-family: Arial; font-size: 14.399999618530273px; line-height: 26px; background-color: #ffffff;"><span style="font-size: 14px;">&nbsp; &nbsp; 因为一般达不到题目所要求的：时间复杂度O(N),空间O(1)，且保证原来正负数之间的相对位置不变。</span><span style="font-size: 14px;">本编程艺术系列第27章就来阐述这个问题，若有任何漏洞，欢迎随时不吝指正。谢谢。</span></p><h3><br /></h3><h3><span style="font-size: 14px;">重新排列使负数排在正数前面</span></h3><p style="color: #333333; font-family: Arial; font-size: 14.399999618530273px; line-height: 26px; background-color: #ffffff;"><span style="font-size: 14px;">原题是这样的：</span></p><p style="color: #333333; font-family: Arial; font-size: 14.399999618530273px; line-height: 26px; background-color: #ffffff;"><span style="font-size: 14px;"><span style="font-size: 14px;"><span style="font-family: 'Arial Black';">一个未排序整数数组，有正负数，重新排列使负数排在正数前面，并且要求不改变原来的正负数之间相对顺序。<br />比如： input: 1,7,-5,9,-12,15 ，ans: -5,-12,1,7,9,15 。且要求时间复杂度O(N),空间O(1) 。</span></span></span></p><p style="color: #333333; font-family: Arial; font-size: 14.399999618530273px; line-height: 26px; background-color: #ffffff;"><span style="font-size: 14px;">&nbsp; &nbsp; OK，下面咱们就来试着一步一步解这道题，如下5种思路（从复杂度O(N^2)到O(N*logN)，从不符合题目条件到一步步趋近于条件)）：</span></p><p style="color: #333333; font-family: Arial; font-size: 14.399999618530273px; line-height: 26px; background-color: #ffffff;"></p><ol style="color: #333333; font-family: Arial; font-size: 14.399999618530273px; line-height: 26px; background-color: #ffffff;"><li>最简单的，如果不考虑时间复杂度，最简单的思路是从头扫描这个数组，每碰到一个正数时，拿出这个数字，并把位于这个数字后面的所有数字往前挪动一位。挪完之后在数组的末尾有一个空位，这时把该正数放入这个空位。由于碰到一个正，需要移动O(n)个数字，因此总的时间复杂度是O(n２)。</li><li>既然题目要求的是把负数放在数组的前半部分，正数放在数组的后半部分，因此所有的负数应该位于正数的前面。也就是说我们在扫描这个数组的时候，如果发现有正数出现在负数的前面，我们可以交换他们的顺序，交换之后就符合要求了。<br />因此我们可以维护两个指针，第一个指针初始化为数组的第一个数字，它只向后移动；第二个指针初始化为数组的最后一个数字，它只向前移动。在两个指针相遇之前，第一个指针总是位于第二个指针的前面。如果第一个指针指向的数字是正而第二个指针指向的数字是负数，我们就交换这两个数字。<br />但遗憾的是上述方法改变了原来正负数之间的相对顺序。所以，咱们得另寻良策<span style="font-family: SimSun; line-height: 25px; font-size: 14px;">。</span></li><li><p dir="ltr" align="left" style="font-size: 14px; margin-top: 0pt; margin-bottom: 0pt;">首先，定义这样一个过程为&#8220;翻转&#8221;：(a1,a2,...,am,b1,b2,...,bn) --&gt; (b1,b2,...,bn,a1,a2,...,am)。其次，对于待处理的未排序整数数组，从头到尾进行扫描，寻找(正正...正负...负负)串；每找到这样一个串，则计数器加1；若计数为奇数，则对当前串做一个&#8220;翻转&#8221;；反复扫描，直到再也找不到(正正...正负...负负)串。</p><p dir="ltr" align="left" style="font-size: 14px; margin-top: 0pt; margin-bottom: 0pt;"><span style="font-size: 14px;"><span style="font-size: 14px;">此思路来自朋友胡果果，<span style="font-size: 14px;">空间复杂度虽为O(1)，</span>但其时间复杂度O(N*logN)。</span>更多具体细节参看原文：<span style="font-size: 14px;"><span style="font-family: 'Comic Sans MS';"><a href="http://qing.weibo.com/1570303725/5d98eeed33000hcb.html" target="_blank" style="color: #336699; text-decoration: initial;">http://qing.weibo.com/1570303725/5d98eeed33000hcb.html</a>。故，不符合题目要求，继续寻找。</span></span></span></p></li><li><div><span style="line-height: 25px; font-size: 14px;"><span style="font-family: SimSun;">我们可以这样，</span></span><span style="font-size: 14px;">设置一个起始点j, 一个翻转点k,一个终止点L，从右侧起，起始点在第一个出现的负数, 翻转点在起始点后第一个出现的正数,终止点在翻转点后出现的第一个负数(或结束)。</span></div><p align="left" style="font-size: 14px;">如果无翻转点, 则不操作，如果有翻转点, 则待终止点出现后, 做翻转, 即ab =&gt; ba 这样的操作。翻转后, 负数串一定在左侧, 然后从负数串的右侧开始记录起始点, 继续往下找下一个翻转点。</p><p align="left" style="font-size: 14px;">例子中的就是(下划线代表要交换顺序的两个数字)：</p><p align="left" style="font-size: 14px;">1, 7, -5,&nbsp;<u>9</u>,&nbsp;<u>-12</u>, 15 &nbsp;<br />第一次翻转: 1,&nbsp;<u>7</u>, -5,&nbsp;<u>-12</u>,9, 15&nbsp;&nbsp; =&gt;&nbsp;&nbsp;<u>1</u>, -12,<u>&nbsp;-5,</u>&nbsp;7, 9, 15<br />第二次翻转: -5, -12, 1, 7, 9, 15</p>此思路2果真解决了么?NO，用下面这个例子试一下，我们就能立马看出了漏洞：<br style="font-size: 14px;" /><span style="font-size: 14px;">1, 7, -5, -6，&nbsp;<u>9</u>,&nbsp;<u>-12</u>, 15（此种情况未能处理）</span><br style="font-size: 14px;" /><span style="font-size: 14px;">1&nbsp;<u>7</u>&nbsp;-5 -6&nbsp;<u>-12</u>&nbsp;9 15</span><br style="font-size: 14px;" /><span style="font-size: 14px;"><u>1&nbsp;</u>-12 -5&nbsp;<u>-6</u>&nbsp;7 9 15</span><br style="font-size: 14px;" /><span style="font-size: 14px;">-6 -12 -5 1 7 9 15 &nbsp; (此时，正负数之间的相对顺序已经改变，本应该是-5，-6，-12，而现在是-6 -12 -5)</span></li><li><span style="font-family: SimSun; line-height: 25px; font-size: 14px;">看来这个问题的确有点麻烦，不过我们最终貌似还是找到了另外一种解决办法，正如朋友超越神所说的：从后往前扫描，遇到负数，开始记录负数区间，然后遇到正数，记录前面的正数区间，然后把整个负数区间与前面的正数区间进行交换，交换区间但保序的算法类似（a,bc-&gt;bc,a）的字符串原地翻转算法。</span><span style="font-family: SimSun; line-height: 25px; font-size: 14px;">交换完之后要继续向前一直扫描下去，每次碰到负数区间在正数区间后面，就翻转区间。下面，将详细阐述此思路4。</span></li></ol><h3><span style="font-family: SimSun;"><span style="line-height: 25px; font-size: 14px;">思路5之区间翻转</span></span></h3><div style="color: #333333; font-family: Arial; font-size: 14.399999618530273px; line-height: 26px; background-color: #ffffff;"><span style="font-family: SimSun;"><span style="line-height: 25px; font-size: 14px;">&nbsp; &nbsp; 其实上述思路5非常简单，既然单个翻转无法解决问题，那么咱们可以区间翻转阿。什么叫区间翻转?不知读者朋友们是否还记得本blog之前曾经整理过这样一道题，微软面试100题系列第10题，如下：</span></span></div><div style="color: #333333; font-family: Arial; font-size: 14.399999618530273px; line-height: 26px; background-color: #ffffff;"><span style="font-family: SimSun;"></span><p dir="ltr" align="left" style="font-size: 14px; margin-top: 0pt; margin-bottom: 0pt;">10、翻转句子中单词的顺序。<br />题目：输入一个英文句子，翻转句子中单词的顺序，但单词内字符的顺序不变。句子中单词以空格符隔开。为简单起见，标点符号和普通字母一样处理。例如输入&#8220;I am a student.&#8221;，则输出&#8220;student. a am I&#8221;。<span style="font-family: 'Arial Black';">而此题可以在O(N)的时间复杂度内解决</span>：</p><p dir="ltr" align="left" style="font-size: 14px; margin-top: 0pt; margin-bottom: 0pt;">&nbsp; &nbsp; 由于本题需要翻转句子，我们先颠倒句子中的所有字符。这时，不但翻转了句子中单词的顺序，而且单词内字符也被翻转了。我们再颠倒每个单词内的字符。由于单词内的字符被翻转两次，因此顺序仍然和输入时的顺序保持一致。<br />&nbsp; &nbsp; 以上面的输入为例：翻转&#8220;I am a student.&#8221;中所有字符得到&#8220;.tneduts a ma I&#8221;，再翻转每个单词中字符的顺序得到&#8220;students. a am I&#8221;，正是符合要求的输出(编码实现，可以参看此文：<a href="http://zhedahht.blog.163.com/blog/static/254111742007289205219/" target="_blank" style="color: #336699; text-decoration: initial;"><span style="font-family: 'Comic Sans MS';">http://zhedahht.blog.163.com/blog/static/254111742007289205219/</span></a>)。<br /></p><p dir="ltr" align="left" style="font-size: 14px; margin-top: 0pt; margin-bottom: 0pt;">&nbsp; &nbsp; 对的，上述思路3就是这个意思，单词翻转便相当于于区间翻转，既如此，咱们来验证下上述思路2中那个测试用例，如下：</p><blockquote dir="ltr" style="margin-right: 0px;"><blockquote dir="ltr" style="margin-right: 0px;"><p dir="ltr" align="left" style="font-size: 14px; margin-top: 0pt; margin-bottom: 0pt;"><span style="font-size: 14px;">1, 7, -5, -6，&nbsp;<u>9</u>,&nbsp;<u>-12</u>, 15</span><br style="font-size: 14px;" /><span style="font-size: 14px;"><span style="color: #3333ff;"><u>1 7</u>&nbsp;<span style="color: #cc0000;"><u>-5 -6 -12</u></span></span>&nbsp;9 15</span><br style="font-size: 14px;" /><span style="font-size: 14px;">-12 -6 -5&nbsp;<u>7 1</u>&nbsp;9 15 &nbsp; (借用单词翻转的方法，先逐个数字翻转，后正负数整体原地翻转)</span><br style="font-size: 14px;" /><span style="font-size: 14px;">-5 -6 -12 1 7 9 15</span></p></blockquote></blockquote><p dir="ltr" align="left" style="font-size: 14px; margin-top: 0pt; margin-bottom: 0pt;"><br /></p><h3><span style="font-size: 14px;">思路5再次被质疑</span></h3><p dir="ltr" align="left" style="font-size: 14px; margin-top: 0pt; margin-bottom: 0pt;"><span style="font-size: 14px;">&nbsp; &nbsp; 但是，我还想再问，问题至此被解决了么?真的被KO了么?NO，咱们来看这样一种情况，正如威士忌所说：</span></p><p dir="ltr" align="left" style="font-size: 14px; margin-top: 0pt; margin-bottom: 0pt;"><span style="font-size: 14px;">看看这个数据，+-+-+-+-+------+，假如Nminus 等于 n/2，由于前面都是+-+-+-，区间交换需要 n/2/2 = n/4次，每次交换是 T(2*(Nminus + Nplus)) &gt;= T(n)，n/4 * T(n) = T(n*n/4)=O(n^2)。</span></p><p dir="ltr" align="left" style="font-size: 14px; margin-top: 0pt; margin-bottom: 0pt;"><span style="font-size: 14px;">&nbsp; &nbsp; 还有一种更坏的情况，就是+-+-+-+-+------+这种数据可能，后面一大堆的负数，前面正负交替。<span style="font-size: 14px;">所以，咱们的美梦再次破灭，路漫漫其修远兮，此题仍然未找到一个完全解决了的方案。</span></span></p></div><img src ="http://www.cppblog.com/mysileng/aggbug/200652.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2013-05-28 17:50 <a href="http://www.cppblog.com/mysileng/archive/2013/05/28/200652.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序员编程艺术-----第二十五章-----二分查找实现（Jon Bentley：90%程序员无法正确实现）</title><link>http://www.cppblog.com/mysileng/archive/2013/05/28/200651.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Tue, 28 May 2013 08:41:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2013/05/28/200651.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/200651.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2013/05/28/200651.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/200651.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/200651.html</trackback:ping><description><![CDATA[<blockquote style="font-family: Arial; font-size: 14.399999618530273px; line-height: 26px; background-color: #ffffff; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><h3>第二十五章：二分查找实现（Jon Bentley：90%程序员无法正确实现）</h3></blockquote></blockquote><p style="color: #333333; font-family: Arial; font-size: 14.399999618530273px; line-height: 26px; background-color: #ffffff;">作者：July<br />出处：结构之法算法之道</p><h3>引言</h3><p style="color: #333333; font-family: Arial; font-size: 14.399999618530273px; line-height: 26px; background-color: #ffffff;">&nbsp; &nbsp;&nbsp;Jon Bentley：90%以上的程序员无法正确无误的写出二分查找代码。也许很多人都早已听说过这句话，但我还是想引用《编程珠玑》上的如下几段文字：&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14.399999618530273px; line-height: 26px; background-color: #ffffff;"><span style="white-space: pre;">	<span style="font-size: 24px;">&#8220;</span></span>二分查找可以解决（<strong>预排序数组的查找</strong>）问题：只要数组中包含T（即要查找的值），那么通过不断缩小包含T的范围，最终就可以找到它。一开始，范围覆盖整个数组。将数组的中间项与T进行比较，可以排除一半元素，范围缩小一半。就这样反复比较，反复缩小范围，最终就会在数组中找到T，或者确定原以为T所在的范围实际为空。对于包含N个元素的表，整个查找过程大约要经过log(2)N次比较。&nbsp;<br /><span style="white-space: pre;">	</span>多数程序员都觉得只要理解了上面的描述，写出代码就不难了；但事实并非如此。如果你不认同这一点，最好的办法就是放下书本，自己动手写一写。试试吧。&nbsp;<br /><span style="white-space: pre;">	</span>我在贝尔实验室和IBM的时候都出过这道考题。那些专业的程序员有几个小时的时间，可以用他们选择的语言把上面的描述写出来；写出高级伪代码也可以。考试结束后，差不多所有程序员都认为自己写出了正确的程序。于是，我们花了半个钟头来看他们编写的代码经过测试用例验证的结果。几次课，一百多人的结果相差无几：90%的程序员写的程序中有bug（我并不认为没有bug的代码就正确）。&nbsp;<br /><span style="white-space: pre;">	</span>我很惊讶：在足够的时间内，只有大约10%的专业程序员可以把这个小程序写对。但写不对这个小程序的还不止这些人：高德纳在《计算机程序设计的艺术 第3卷 排序和查找》第6.2.1节的&#8220;历史与参考文献&#8221;部分指出，虽然早在1946年就有人将二分查找的方法公诸于世，但直到1962年才有人写出没有bug的二分查找程序。<span style="font-size: 24px;">&#8221;</span>&#8212;&#8212;乔恩&#183;本特利，《编程珠玑（第1版）》第35-36页。</p><p style="color: #333333; font-family: Arial; font-size: 14.399999618530273px; line-height: 26px; background-color: #ffffff;">&nbsp; &nbsp; 你能正确无误的写出二分查找代码么？不妨一试。</p><h3>二分查找代码</h3><p style="color: #333333; font-family: Arial; font-size: 14.399999618530273px; line-height: 26px; background-color: #ffffff;">&nbsp; &nbsp; &nbsp;二分查找的原理想必不用多解释了，不过有一点必须提醒读者的是，二分查找是针对的排好序的数组。OK，纸上读来终觉浅，觉知此事要躬行。我先来写一份，下面是我写的一份二分查找的实现（之前去某一家公司面试也曾被叫当场实现二分查找，不过结果可能跟你一样，当时就未能完整无误写出），有任何问题或错误，恳请不吝指正：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008000; ">//</span><span style="color: #008000; ">二分查找V0.1实现版&nbsp;&nbsp;<br /></span><span style="color: #008000; ">//</span><span style="color: #008000; ">copyright@2011&nbsp;July&nbsp;&nbsp;<br /></span><span style="color: #008000; ">//</span><span style="color: #008000; ">随时欢迎读者找bug，email：zhoulei0907@yahoo.cn。&nbsp;&nbsp;<br />&nbsp;&nbsp;<br /></span><span style="color: #008000; ">//</span><span style="color: #008000; ">首先要把握下面几个要点：&nbsp;&nbsp;<br /></span><span style="color: #008000; ">//</span><span style="color: #008000; ">right=n-1&nbsp;=&gt;&nbsp;while(left&nbsp;&lt;=&nbsp;right)&nbsp;=&gt;&nbsp;right=middle-1;&nbsp;&nbsp;<br /></span><span style="color: #008000; ">//</span><span style="color: #008000; ">right=n&nbsp;&nbsp;&nbsp;=&gt;&nbsp;while(left&nbsp;&lt;&nbsp;&nbsp;right)&nbsp;=&gt;&nbsp;right=middle;&nbsp;&nbsp;<br /></span><span style="color: #008000; ">//</span><span style="color: #008000; ">middle的计算不能写在while循环外，否则无法得到更新。&nbsp;&nbsp;</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;<br /></span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;binary_search(</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;array[],</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;n,</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;value)&nbsp;&nbsp;<br />{&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;left</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;right</span><span style="color: #000000; ">=</span><span style="color: #000000; ">n</span><span style="color: #000000; ">-</span><span style="color: #000000; ">1</span><span style="color: #000000; ">;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">如果这里是int&nbsp;right&nbsp;=&nbsp;n&nbsp;的话，那么下面有两处地方需要修改，以保证一一对应：&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">1、下面循环的条件则是while(left&nbsp;&lt;&nbsp;right)&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">2、循环内当array[middle]&gt;value&nbsp;的时候，right&nbsp;=&nbsp;mid&nbsp;&nbsp;</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">while</span><span style="color: #000000; ">&nbsp;(left</span><span style="color: #000000; ">&lt;=</span><span style="color: #000000; ">right)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">循环条件，适时而变&nbsp;&nbsp;</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;middle</span><span style="color: #000000; ">=</span><span style="color: #000000; ">left&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;((right</span><span style="color: #000000; ">-</span><span style="color: #000000; ">left)</span><span style="color: #000000; ">&gt;&gt;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">);&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">防止溢出，移位也更高效。同时，每次循环都需要更新。&nbsp;&nbsp;</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(array[middle]</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">value)&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;right&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">middle</span><span style="color: #000000; ">-</span><span style="color: #000000; ">1</span><span style="color: #000000; ">;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">right赋值，适时而变&nbsp;&nbsp;</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">else</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">(array[middle]</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">value)&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;left</span><span style="color: #000000; ">=</span><span style="color: #000000; ">middle</span><span style="color: #000000; ">+</span><span style="color: #000000; ">1</span><span style="color: #000000; ">;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">else</span><span style="color: #000000; ">&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;middle;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">可能会有读者认为刚开始时就要判断相等，但毕竟数组中不相等的情况更多&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">如果每次循环都判断一下是否相等，将耗费时间&nbsp;&nbsp;</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">1</span><span style="color: #000000; ">;&nbsp;&nbsp;<br />} &nbsp;</span></div><br /><br /></p><img src ="http://www.cppblog.com/mysileng/aggbug/200651.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2013-05-28 16:41 <a href="http://www.cppblog.com/mysileng/archive/2013/05/28/200651.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序员编程艺术-----第二十三 ~ 二十四章-----杨氏矩阵、不重复Hash编码</title><link>http://www.cppblog.com/mysileng/archive/2013/05/28/200650.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Tue, 28 May 2013 08:39:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2013/05/28/200650.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/200650.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2013/05/28/200650.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/200650.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/200650.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp; 第二十三、四章：杨氏矩阵查找，倒排索引关键词Hash不重复编码实践作者：July、yansha。编程艺术室出品。出处：结构之法算法之道。前言&nbsp; &nbsp; 本文阐述两个问题，第二十三章是杨氏矩阵查找问题，第二十四章是有关倒排索引中关键词Hash编码的问题，主要要解决不重复以及追加的功能，同时也是经典算法研究系列十一、从头到尾彻底解析Hash表算法之续。&nbsp; &nb...&nbsp;&nbsp;<a href='http://www.cppblog.com/mysileng/archive/2013/05/28/200650.html'>阅读全文</a><img src ="http://www.cppblog.com/mysileng/aggbug/200650.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2013-05-28 16:39 <a href="http://www.cppblog.com/mysileng/archive/2013/05/28/200650.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序员编程艺术-----第十五 ~ 二十章-----全排列、跳台阶、奇偶、第一个出现一次字符、一致性hash</title><link>http://www.cppblog.com/mysileng/archive/2013/05/16/200324.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Thu, 16 May 2013 08:42:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2013/05/16/200324.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/200324.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2013/05/16/200324.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/200324.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/200324.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 第十六~第二十章：全排列，跳台阶，奇偶排序，第一个只出现一次等问题作者：July、2011.10.16。出处：http://blog.csdn.net/v_JULY_v。引言&nbsp; &nbsp; 最近这几天闲职在家，一忙着投简历，二为准备面试而搜集整理各种面试题。故常常关注个人所建的Algorithms1-14群内朋友关于笔试，面试，宣讲会，offer，薪资的讨论以及在群内发布的各种笔/面试...&nbsp;&nbsp;<a href='http://www.cppblog.com/mysileng/archive/2013/05/16/200324.html'>阅读全文</a><img src ="http://www.cppblog.com/mysileng/aggbug/200324.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2013-05-16 16:42 <a href="http://www.cppblog.com/mysileng/archive/2013/05/16/200324.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序员编程艺术-----第十一 ~ 十四章-----海量整数处理、蓄水池抽样、回文 </title><link>http://www.cppblog.com/mysileng/archive/2013/05/15/200299.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Wed, 15 May 2013 13:37:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2013/05/15/200299.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/200299.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2013/05/15/200299.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/200299.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/200299.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp; &nbsp; &nbsp; &nbsp;程序员编程艺术第十二~十五章：中签概率，IP访问次数，回文等问题（初稿）作者：上善若水.qinyu，BigPotato，luuillu，well，July。编程艺术室出品。前言&nbsp;&nbsp;&nbsp; 本文的全部稿件是由我们编程艺术室的部分成员：上善若水.qinyu，BigPotato，luuillu，well，July共同完成，共...&nbsp;&nbsp;<a href='http://www.cppblog.com/mysileng/archive/2013/05/15/200299.html'>阅读全文</a><img src ="http://www.cppblog.com/mysileng/aggbug/200299.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2013-05-15 21:37 <a href="http://www.cppblog.com/mysileng/archive/2013/05/15/200299.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序员编程艺术-----第十章-----最长公共子序列(LCS)问题</title><link>http://www.cppblog.com/mysileng/archive/2013/05/14/200265.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Tue, 14 May 2013 14:05:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2013/05/14/200265.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/200265.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2013/05/14/200265.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/200265.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/200265.html</trackback:ping><description><![CDATA[<blockquote dir="ltr" style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff; margin-right: 0px;"><blockquote dir="ltr" style="margin-right: 0px;"><h2>&nbsp; 程序员编程艺术第十一章：最长公共子序列(LCS)问题</h2></blockquote></blockquote><h3><span style="color: #990000;">0、前言</span></h3><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 程序员编程艺术系列重新开始创作了（前十章，请参考<a href="http://blog.csdn.net/v_JULY_v/archive/2011/06/02/6460494.aspx" target="_blank" style="color: #336699; text-decoration: initial;"><strong>程序员编程艺术第一~十章集锦与总结</strong></a>）。回顾之前的前十章，有些代码是值得商榷的，因当时的代码只顾阐述算法的原理或思想，所以，很多的与代码规范相关的问题都未能做到完美。日后，会着力修缮之。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 搜遍网上，讲解这个LCS问题的文章不计其数，但大多给读者一种并不友好的感觉，稍感晦涩，且代码也不够清晰。本文力图避免此些情况。力保通俗，阐述详尽。同时，经典算法研究系列的第三章（<a href="http://blog.csdn.net/v_JULY_v/archive/2010/12/31/6110269.aspx" target="_blank" style="color: #336699; text-decoration: initial;">三、dynamic programming</a>）也论述了此LCS问题。有任何问题，欢迎不吝赐教。</p><h3><span style="color: #990000;">第一节、问题描述</span></h3><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 什么是最长公共子序列呢?好比一个数列&nbsp;<em>S</em>，如果分别是两个或多个已知数列的子序列，且是所有符合此条件序列中最长的，则<em>S</em>&nbsp;称为已知序列的最长公共子序列。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 举个例子，如：有两条随机序列，如 1 3 4 5 5 ，and 2 4 5 5 7 6，则它们的最长公共子序列便是：4 5 5。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 注意最长公共子串（Longest CommonSubstring）和最长公共子序列（LongestCommon Subsequence, LCS）的区别：子串（Substring）是串的一个连续的部分，子序列（Subsequence）则是从不改变序列的顺序，而从序列中去掉任意的元素而获得的新序列；更简略地说，前者（子串）的字符的位置必须连续，后者（子序列LCS）则不必。比如字符串acdfg同akdfc的最长公共子串为df，而他们的最长公共子序列是adf。LCS可以使用动态规划法解决。下文具体描述。</p><h3><span style="color: #990000;">第二节、LCS问题的解决思路</span></h3><ul style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><li><h4>穷举法&nbsp;&nbsp;&nbsp;</h4></li></ul><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 解最长公共子序列问题时最容易想到的算法是穷举搜索法，即对X的每一个子序列，检查它是否也是Y的子序列，从而确定它是否为X和Y的公共子序列，并且在检查过程中选出最长的公共子序列。X和Y的所有子序列都检查过后即可求出X和Y的最长公共子序列。X的一个子序列相应于下标序列{1, 2, &#8230;, m}的一个子序列，因此，X共有2<sup>m</sup>个不同子序列（Y亦如此，如为2^n），从而穷举搜索法需要指数时间（2^m * 2^n）。</p><ul style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><li><strong>动态规划算法</strong></li></ul><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 事实上，最长公共子序列问题也有最优子结构性质。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">记:</p><blockquote dir="ltr" style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff; margin-right: 0px;"><p>Xi=﹤x1，&#8943;，xi﹥即X序列的前i个字符 (1&#8804;i&#8804;m)（前缀）</p><p>Yj=﹤y1，&#8943;，yj﹥即Y序列的前j个字符 (1&#8804;j&#8804;n)（前缀）</p></blockquote><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">假定Z=﹤z1，&#8943;，zk﹥&#8712;LCS(X , Y)。</p><ul style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><li><p>若<strong>xm=yn</strong>（最后一个字符相同），则不难用反证法证明：该字符必是X与Y的任一最长公共子序列Z（设长度为k）的最后一个字符，即有zk = xm = yn 且显然有Zk-1&#8712;LCS(Xm-1 , Yn-1)即Z的前缀<strong>Zk-1是Xm-1与Yn-1的最长公共子序列</strong>。此时，问题化归成求Xm-1与Yn-1的LCS（<em>LCS(X , Y)的长度等于LCS(Xm-1 , Yn-1</em>)的长度加1）。</p></li><li><p>若<strong>xm&#8800;yn</strong>，则亦不难用反证法证明：要么Z&#8712;LCS(Xm-1, Y)，要么Z&#8712;LCS(X , Yn-1)。由于zk&#8800;xm与zk&#8800;yn其中至少有一个必成立，若zk&#8800;xm则有Z&#8712;LCS(Xm-1 , Y)，类似的，若zk&#8800;yn 则有Z&#8712;LCS(X , Yn-1)。此时，问题化归成求Xm-1与Y的LCS及X与Yn-1的LCS。LCS(X , Y)的长度为：max{LCS(Xm-1 , Y)的长度, LCS(X , Yn-1)的长度}。</p></li></ul><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 由于上述当<strong>xm&#8800;yn</strong>的情况中，求LCS(Xm-1 , Y)的长度与LCS(X , Yn-1)的长度，这两个问题不是相互独立的：两者都需要求LCS(Xm-1，Yn-1)的长度。另外两个序列的LCS中包含了两个序列的前缀的LCS，故问题具有最优子结构性质考虑用动态规划法。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 也就是说，解决这个LCS问题，你要求三个方面的东西：<u><strong>1</strong>、LCS（Xm-1，Yn-1）+1；<strong>2</strong>、LCS（Xm-1，Y），LCS（X，Yn-1）；<strong>3</strong>、max{LCS（Xm-1，Y），LCS（X，Yn-1）}</u>。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 行文至此，其实对这个LCS的动态规划解法已叙述殆尽，不过，为了成书的某种必要性，下面，我试着再多加详细阐述这个问题。</p><h3><span style="color: #990000;">第三节、动态规划算法解LCS问题</span></h3><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><strong>3.1、最长公共子序列的结构</strong></p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 最长公共子序列的结构有如下表示：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 设序列X=&lt;x<sub>1</sub>, x<sub>2</sub>, &#8230;, x<sub>m</sub>&gt;和Y=&lt;y<sub>1</sub>, y<sub>2</sub>, &#8230;, y<sub>n</sub>&gt;的一个最长公共子序列Z=&lt;z<sub>1</sub>, z<sub>2</sub>, &#8230;, z<sub>k</sub>&gt;，则：</p><ol style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><li>若x<sub>m</sub>=y<sub>n</sub>，则z<sub>k</sub>=x<sub>m</sub>=y<sub>n</sub>且Z<sub>k-1</sub>是X<sub>m-1</sub>和Y<sub>n-1</sub>的最长公共子序列；</li><li>若x<sub>m</sub>&#8800;y<sub>n</sub>且z<sub>k</sub>&#8800;x<sub>m ，</sub>则Z是X<sub>m-1</sub>和Y的最长公共子序列；</li><li>若x<sub>m</sub>&#8800;y<sub>n</sub>且z<sub>k</sub>&#8800;y<sub>n</sub>&nbsp;，则Z是X和Y<sub>n-1</sub>的最长公共子序列。</li></ol><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 其中X<sub>m-1</sub>=&lt;x<sub>1</sub>, x<sub>2</sub>, &#8230;, x<sub>m-1</sub>&gt;，Y<sub>n-1</sub>=&lt;y<sub>1</sub>, y<sub>2</sub>, &#8230;, y<sub>n-1</sub>&gt;，Z<sub>k-1</sub>=&lt;z<sub>1</sub>, z<sub>2</sub>, &#8230;, z<sub>k-1</sub>&gt;。</p><h4>3、2.子问题的递归结构</h4><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 由最长公共子序列问题的最优子结构性质可知，要找出X=&lt;x<sub>1</sub>, x<sub>2</sub>, &#8230;, x<sub>m</sub>&gt;和Y=&lt;y<sub>1</sub>, y<sub>2</sub>, &#8230;, y<sub>n</sub>&gt;的最长公共子序列，可按以下方式递归地进行：当x<sub>m</sub>=y<sub>n</sub>时，找出X<sub>m-1</sub>和Y<sub>n-1</sub>的最长公共子序列，然后在其尾部加上x<sub>m</sub>(=y<sub>n</sub>)即可得X和Y的一个最长公共子序列。当x<sub>m</sub>&#8800;y<sub>n</sub>时，必须解两个子问题，即找出X<sub>m-1</sub>和Y的一个最长公共子序列及X和Y<sub>n-1</sub>的一个最长公共子序列。这两个公共子序列中较长者即为X和Y的一个最长公共子序列。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 由此递归结构容易看到最长公共子序列问题具有子问题重叠性质。例如，在计算X和Y的最长公共子序列时，可能要计算出X和Y<sub>n-1</sub>及X<sub>m-1</sub>和Y的最长公共子序列。而这两个子问题都包含一个公共子问题，即计算X<sub>m-1</sub>和Y<sub>n-1</sub>的最长公共子序列。</p><p dir="ltr" style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff; margin-right: 0px;">&nbsp;&nbsp;&nbsp; 与矩阵连乘积最优计算次序问题类似，我们来建立子问题的最优值的递归关系。用c[i,j]记录序列X<sub>i</sub>和Y<sub>j</sub>的最长公共子序列的长度。其中X<sub>i</sub>=&lt;x<sub>1</sub>, x<sub>2</sub>, &#8230;, x<sub>i</sub>&gt;，Y<sub>j</sub>=&lt;y<sub>1</sub>, y<sub>2</sub>, &#8230;, y<sub>j</sub>&gt;。当i=0或j=0时，空序列是X<sub>i</sub>和Y<sub>j</sub>的最长公共子序列，故c[i,j]=0。其他情况下，由定理可建立递归关系如下：<br /><img src="http://www.cppblog.com/images/cppblog_com/mysileng/QQ截图20130514220052.jpg" width="401" height="86" alt="" /><br /></p><h4>3、3.计算最优值</h4><p style="font-size: 14px;">&nbsp;&nbsp;&nbsp; 直接利用上节节末的递归式，我们将很容易就能写出一个计算c[i,j]的递归算法，但其计算时间是随输入长度指数增长的。由于在所考虑的子问题空间中，总共只有<em>&#952;</em>(<em>m*n</em>)个不同的子问题，因此，用动态规划算法自底向上地计算最优值能提高算法的效率。</p><p style="font-size: 14px;">&nbsp;&nbsp;&nbsp; 计算最长公共子序列长度的动态规划算法LCS_LENGTH(X,Y)以序列X=&lt;x<sub>1</sub>, x<sub>2</sub>, &#8230;, x<sub>m</sub>&gt;和Y=&lt;y<sub>1</sub>, y<sub>2</sub>, &#8230;, y<sub>n</sub>&gt;作为输入。输出两个数组c[0..m ,0..n]和b[1..m ,1..n]。其中c[i,j]存储X<sub>i</sub>与Y<sub>j</sub>的最长公共子序列的长度，b[i,j]记录指示c[i,j]的值是由哪一个子问题的解达到的，这在构造最长公共子序列时要用到。最后，X和Y的最长公共子序列的长度记录于c[m,n]中。</p><div bg_cpp"="" style="border: 1px dashed #999999; background-color: #f5f5f5; width: 687.0499877929688px;"><ol start="1" style="margin-bottom: 0px; margin-left: 0px; padding-top: 5px; padding-bottom: 5px; position: relative;"><li style="border-left-style: none; line-height: 13px;">Procedure&nbsp;LCS_LENGTH(X,Y);&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">begin&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;m:=length[X];&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;n:=length[Y];&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;<span style="color: #0000ff;">for</span>&nbsp;i:=1&nbsp;to&nbsp;m&nbsp;<span style="color: #0000ff;">do</span>&nbsp;c[i,0]:=0;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;<span style="color: #0000ff;">for</span>&nbsp;j:=1&nbsp;to&nbsp;n&nbsp;<span style="color: #0000ff;">do</span>&nbsp;c[0,j]:=0;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;<span style="color: #0000ff;">for</span>&nbsp;i:=1&nbsp;to&nbsp;m&nbsp;<span style="color: #0000ff;">do</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>&nbsp;j:=1&nbsp;to&nbsp;n&nbsp;<span style="color: #0000ff;">do</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>&nbsp;x[i]=y[j]&nbsp;then&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c[i,j]:=c[i-1,j-1]+1;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b[i,j]:=<span style="color: #009900;">"&#8598;"</span>;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">else</span>&nbsp;<span style="color: #0000ff;">if</span>&nbsp;c[i-1,j]&#8805;c[i,j-1]&nbsp;then&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c[i,j]:=c[i-1,j];&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b[i,j]:=<span style="color: #009900;">"&#8593;"</span>;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">else</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c[i,j]:=c[i,j-1];&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b[i,j]:=<span style="color: #009900;">"&#8592;"</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;<span style="color: #0000ff;">return</span>(c,b);&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">end;&nbsp;&nbsp;&nbsp;</li></ol></div><p style="font-size: 14px;">&nbsp;&nbsp;&nbsp; 由算法LCS_LENGTH计算得到的数组b可用于快速构造序列X=&lt;x<sub>1</sub>, x<sub>2</sub>, &#8230;, x<sub>m</sub>&gt;和Y=&lt;y<sub>1</sub>, y<sub>2</sub>, &#8230;, y<sub>n</sub>&gt;的最长公共子序列。首先从b[m,n]开始，沿着其中的箭头所指的方向在数组b中搜索。</p><ul style="font-size: 14px;"><li>当b[i,j]中遇到"&#8598;"时（<em>意味着xi=yi是LCS的一个元素</em>），表示X<sub>i</sub>与Y<sub>j</sub>的最长公共子序列是由X<sub>i-1</sub>与Y<sub>j-1</sub>的最长公共子序列在尾部加上x<sub>i</sub>得到的子序列；</li><li>当b[i,j]中遇到"&#8593;"时，表示X<sub>i</sub>与Y<sub>j</sub>的最长公共子序列和X<sub>i-1</sub>与Y<sub>j</sub>的最长公共子序列相同；</li><li>当b[i,j]中遇到"&#8592;"时，表示X<sub>i</sub>与Y<sub>j</sub>的最长公共子序列和X<sub>i</sub>与Y<sub>j-1</sub>的最长公共子序列相同。</li></ul><p style="font-size: 14px;">&nbsp;&nbsp;&nbsp; 这种方法是按照反序来找LCS的每一个元素的。由于每个数组单元的计算耗费<em>&#927;</em>(1)时间，算法LCS_LENGTH耗时<em>&#927;</em>(<em>mn</em>)。</p><h4>3、4.构造最长公共子序列</h4><p style="font-size: 14px;">&nbsp;&nbsp;&nbsp; 下面的算法LCS(b,X,i,j)实现根据b的内容打印出X<sub>i</sub>与Y<sub>j</sub>的最长公共子序列。通过算法的调用LCS(b,X,length[X],length[Y])，便可打印出序列X和Y的最长公共子序列。</p><div bg_cpp"="" style="border: 1px dashed #999999; background-color: #f5f5f5; width: 687.0499877929688px;"><ol start="1" style="margin-bottom: 0px; margin-left: 0px; padding-top: 5px; padding-bottom: 5px; position: relative;"><li style="border-left-style: none; line-height: 13px;">Procedure&nbsp;LCS(b,X,i,j);&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">begin&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;<span style="color: #0000ff;">if</span>&nbsp;i=0&nbsp;or&nbsp;j=0&nbsp;then&nbsp;<span style="color: #0000ff;">return</span>;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;<span style="color: #0000ff;">if</span>&nbsp;b[i,j]=<span style="color: #009900;">"&#8598;"</span>&nbsp;then&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;begin&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LCS(b,X,i-1,j-1);&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print(x[i]);&nbsp;{打印x[i]}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;<span style="color: #0000ff;">else</span>&nbsp;<span style="color: #0000ff;">if</span>&nbsp;b[i,j]=<span style="color: #009900;">"&#8593;"</span>&nbsp;then&nbsp;LCS(b,X,i-1,j)&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">else</span>&nbsp;LCS(b,X,i,j-1);&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">end;&nbsp;&nbsp;&nbsp;</li></ol></div><p style="font-size: 14px;">在算法LCS中，每一次的递归调用使i或j减1，因此算法的计算时间为<em>O</em>(m+n)。</p><p style="font-size: 14px;">例如，设所给的两个序列为X=&lt;A，B，C，B，D，A，B&gt;和Y=&lt;B，D，C，A，B，A&gt;。由算法LCS_LENGTH和LCS计算出的结果如下图所示：</p><img src="http://www.cppblog.com/images/cppblog_com/mysileng/QQ截图20130514220212.jpg" width="386" height="386" alt="" /><br /><p dir="ltr" style="font-size: 14px;">&nbsp;<em>我来说明下此图（参考算法导论）</em>。在序列X={A，B，C，B，D，A，B}和 Y={B，D，C，A，B，A}上，由LCS_LENGTH计算出的表c和b。第i行和第j列中的方块包含了c[i，j]的值以及指向b[i，j]的箭头。在c[7,6]的项4，表的右下角为X和Y的一个LCS&lt;B，C，B，A&gt;的长度。对于i，j&gt;0，项c[i，j]仅依赖于是否有xi=yi，及项c[i-1，j]和c[i，j-1]的值，这几个项都在c[i，j]之前计算。为了重构一个LCS的元素，从右下角开始跟踪b[i，j]的箭头即可，这条路径标示为阴影，这条路径上的每一个&#8220;&#8598;&#8221;对应于一个使xi=yi为一个LCS的成员的项（高亮标示）。</p><p dir="ltr" style="font-size: 14px;">&nbsp;&nbsp;&nbsp; 所以根据上述图所示的结果，程序将最终输出：&#8220;B C B A&#8221;。</p><h4>3、5.算法的改进</h4><p style="font-size: 14px;">&nbsp;&nbsp;&nbsp; 对于一个具体问题，按照一般的算法设计策略设计出的算法，往往在算法的时间和空间需求上还可以改进。这种改进，通常是利用具体问题的一些特殊性。</p><p style="font-size: 14px;">&nbsp;&nbsp;&nbsp; 例如，在算法LCS_LENGTH和LCS中，可进一步将数组b省去。事实上，数组元素c[i,j]的值仅由c[i-1,j-1]，c[i-1,j]和c[i,j-1]三个值之一确定，而数组元素b[i,j]也只是用来指示c[i,j]究竟由哪个值确定。因此，在算法LCS中，我们可以不借助于数组b而借助于数组c本身临时判断c[i,j]的值是由c[i-1,j-1]，c[i-1,j]和c[i,j-1]中哪一个数值元素所确定，代价是<em>&#927;</em>(1)时间。既然b对于算法LCS不是必要的，那么算法LCS_LENGTH便不必保存它。这一来，可节省<em>&#952;</em>(mn)的空间，而LCS_LENGTH和LCS所需要的时间分别仍然是<em>&#927;</em>(mn)和<em>&#927;</em>(m+n)。不过，由于数组c仍需要<em>&#927;</em>(mn)的空间，因此这里所作的改进，只是在空间复杂性的常数因子上的改进。</p><p style="font-size: 14px;">&nbsp;&nbsp;&nbsp; 另外，如果只需要计算最长公共子序列的长度，则算法的空间需求还可大大减少。事实上，在计算c[i,j]时，只用到数组c的第i行和第i-1行。因此，只要用2行的数组空间就可以计算出最长公共子序列的长度。更进一步的分析还可将空间需求减至min(m, n)。</p><h3><span style="color: #990000;">第四节、编码实现LCS问题</span></h3><p style="font-size: 14px;">&nbsp;&nbsp;&nbsp; 动态规划的一个计算最长公共子序列的方法如下，以两个序列&nbsp;<em>X</em>、<em>Y</em>&nbsp;为例子：</p><p style="font-size: 14px;">设有二维数组&nbsp;<em>f</em>[<em>i</em>][<em>j</em>]&nbsp;表示&nbsp;<em>X</em>&nbsp;的&nbsp;<em>i</em>&nbsp;位和&nbsp;<em>Y</em>&nbsp;的&nbsp;<em>j</em>&nbsp;位之前的最长公共子序列的长度，则有：</p><dl style="font-size: 14px;"><dd><em>f</em>[1][1] =&nbsp;<em>same</em>(1,1)<br /></dd><dd><em>f</em>[<em>i</em>][<em>j</em>] =&nbsp;<em>max</em>{<strong><em>f</em>[<em>i</em>&nbsp;&#8722; 1][<em>j</em>&nbsp;&#8722; 1] +<em>same</em>(<em>i</em>,<em>j</em>)</strong>,&nbsp;<strong><em>f</em>[<em>i</em>&nbsp;&#8722; 1][<em>j</em>]</strong>&nbsp;,<strong><em>f</em>[<em>i</em>][<em>j</em>&nbsp;&#8722; 1]</strong>}</dd></dl><p style="font-size: 14px;">其中，<em>same</em>(<em>a</em>,<em>b</em>)当&nbsp;<em>X</em>&nbsp;的第&nbsp;<em>a</em>&nbsp;位与&nbsp;<em>Y</em>&nbsp;的第&nbsp;<em>b</em>&nbsp;位完全相同时为&#8220;1&#8221;，否则为&#8220;0&#8221;。</p><p style="font-size: 14px;">此时，<em>f</em>[<em>i</em>][<em>j</em>]中最大的数便是&nbsp;<em>X</em>&nbsp;和&nbsp;<em>Y</em>&nbsp;的最长公共子序列的长度，依据该数组回溯，便可找出最长公共子序列。</p><p style="font-size: 14px;">该算法的空间、时间复杂度均为<em>O</em>(<em>n</em><sup>2</sup>)，经过优化后，空间复杂度可为<em>O</em>(<em>n</em>)，时间复杂度为<em>O</em>(<em>n</em>log<em>n</em>)。</p><p style="font-size: 14px;">以下是此算法的java代码：</p><div bg_cpp"="" style="border: 1px dashed #999999; background-color: #f5f5f5; width: 687.0499877929688px;"><ol start="1" style="margin-bottom: 0px; margin-left: 0px; padding-top: 5px; padding-bottom: 5px; position: relative;"><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">import&nbsp;java.util.Random;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #0000ff;">public</span>&nbsp;<span style="color: #0000ff;">class</span>&nbsp;LCS{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">public</span>&nbsp;<span style="color: #0000ff;">static</span>&nbsp;<span style="color: #0000ff;">void</span>&nbsp;main(String[]&nbsp;args){&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//设置字符串长度</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;substringLength1&nbsp;=&nbsp;20;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;substringLength2&nbsp;=&nbsp;20;&nbsp;&nbsp;<span style="color: #999999;">//具体大小可自行设置</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//&nbsp;随机生成字符串</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;x&nbsp;=&nbsp;GetRandomStrings(substringLength1);&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;y&nbsp;=&nbsp;GetRandomStrings(substringLength2);&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Long&nbsp;startTime&nbsp;=&nbsp;System.nanoTime();&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//&nbsp;构造二维数组记录子问题x[i]和y[i]的LCS的长度</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>[][]&nbsp;opt&nbsp;=&nbsp;<span style="color: #0000ff;">new</span>&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>[substringLength1&nbsp;+&nbsp;1][substringLength2&nbsp;+&nbsp;1];&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//&nbsp;动态规划计算所有子问题</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>&nbsp;(<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;i&nbsp;=&nbsp;substringLength1&nbsp;-&nbsp;1;&nbsp;i&nbsp;&gt;=&nbsp;0;&nbsp;i--){&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>&nbsp;(<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;j&nbsp;=&nbsp;substringLength2&nbsp;-&nbsp;1;&nbsp;j&nbsp;&gt;=&nbsp;0;&nbsp;j--){&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>&nbsp;(x.charAt(i)&nbsp;==&nbsp;y.charAt(j))&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;opt[i][j]&nbsp;=&nbsp;opt[i&nbsp;+&nbsp;1][j&nbsp;+&nbsp;1]&nbsp;+&nbsp;1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//参考上文我给的公式。</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">else</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;opt[i][j]&nbsp;=&nbsp;Math.max(opt[i&nbsp;+&nbsp;1][j],&nbsp;opt[i][j&nbsp;+&nbsp;1]);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//参考上文我给的公式。</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-------------------------------------------------------------------------------------&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;理解上段，参考上文我给的公式：&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;根据上述结论，可得到以下公式，&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果我们记字符串Xi和Yj的LCS的长度为c[i,j]，我们可以递归地求c[i,j]：&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>&nbsp;i&lt;0&nbsp;or&nbsp;j&lt;0&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c[i,j]=&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c[i-1,j-1]+1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>&nbsp;i,j&gt;=0&nbsp;and&nbsp;xi=xj&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;max(c[i,j-1],c[i-1,j]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>&nbsp;i,j&gt;=0&nbsp;and&nbsp;xi&#8800;xj&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-------------------------------------------------------------------------------------&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: #009900;">"substring1:"</span>+x);&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: #009900;">"substring2:"</span>+y);&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.print(<span style="color: #009900;">"LCS:"</span>);&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;i&nbsp;=&nbsp;0,&nbsp;j&nbsp;=&nbsp;0;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">while</span>&nbsp;(i&nbsp;&lt;&nbsp;substringLength1&nbsp;&amp;&amp;&nbsp;j&nbsp;&lt;&nbsp;substringLength2){&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>&nbsp;(x.charAt(i)&nbsp;==&nbsp;y.charAt(j)){&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.print(x.charAt(i));&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i++;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j++;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000ff;">else</span>&nbsp;<span style="color: #0000ff;">if</span>&nbsp;(opt[i&nbsp;+&nbsp;1][j]&nbsp;&gt;=&nbsp;opt[i][j&nbsp;+&nbsp;1])&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i++;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">else</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j++;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Long&nbsp;endTime&nbsp;=&nbsp;System.nanoTime();&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: #009900;">"&nbsp;Totle&nbsp;time&nbsp;is&nbsp;"</span>&nbsp;+&nbsp;(endTime&nbsp;-&nbsp;startTime)&nbsp;+&nbsp;<span style="color: #009900;">"&nbsp;ns"</span>);&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//取得定长随机字符串</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">public</span>&nbsp;<span style="color: #0000ff;">static</span>&nbsp;String&nbsp;GetRandomStrings(<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;length){&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringBuffer&nbsp;buffer&nbsp;=&nbsp;<span style="color: #0000ff;">new</span>&nbsp;StringBuffer(<span style="color: #009900;">"abcdefghijklmnopqrstuvwxyz"</span>);&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringBuffer&nbsp;sb&nbsp;=&nbsp;<span style="color: #0000ff;">new</span>&nbsp;StringBuffer();&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Random&nbsp;r&nbsp;=&nbsp;<span style="color: #0000ff;">new</span>&nbsp;Random();&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;range&nbsp;=&nbsp;buffer.length();&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>&nbsp;(<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;length;&nbsp;i++){&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sb.append(buffer.charAt(r.nextInt(range)));&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;sb.toString();&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">}&nbsp;&nbsp;</li></ol></div><h3><span style="color: #990000;">第五节、改进的算法</span></h3><p dir="ltr" style="font-size: 14px;">&nbsp;&nbsp;&nbsp; 下面咱们来了解一种不同于动态规划法的一种新的求解最长公共子序列问题的方法,该算法主要是把求解公共字符串问题转化为求解矩阵L(p,m)的问题，在利用定理求解矩阵的元素过程中（1）while(i&lt;k),L(k,i)=null，<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （2）while(L(k,i)=k),L(k,i+1)=L(k,i+2)=&#8230;L(k,m)=k；</p><p dir="ltr" style="font-size: 14px;">&nbsp;&nbsp;&nbsp; 求出每列元素，一直到发现第p+1 行都为null 时退出循环，得出矩阵L(k,m)后，B[L(1,m-p+1)]B[L(2,m-p+2)]&#8230;B[L(p,m)]即为A 和B 的LCS，其中p 为LCS 的长度。</p><p style="font-size: 14px;"><strong>6.1 主要定义及定理</strong></p><ul style="font-size: 14px;"><li>定义 1 子序列(Subsequence)：给定字符串A=A[1]A[2]&#8230;A[m]，(A[i]是A 的第i 个字母，A[i]&#8712;字符集&#931;，l&lt;= i&lt;m = A ， A 表示字符串A 的长度)，字符串B 是A 的子序列是指B=A[ 1 i ]A[ 2 i ]&#8230;A[ k i ],其中1 i &lt; 2 i &lt;&#8230;&lt; k i 且k&lt;=m.</li><li>定义2 公共子序列(Common Subsequence)：给定字符串A、B、C，C 称为A 和B 的公共子序列是指C 既是A 的子序列，又是B 的子序列。</li><li>定义3 最长公共子序列(Longest Common Subsequence 简称LCS)：给定字符串A、B、C，C 称为A 和B 的最长公共子序列是指C 是A 和B 的公共子序列，且对于A 和B 的任意公共子序列D，都有D &lt;= C 。给定字符串A 和B，A =m，B =n，不妨设m&lt;=n，LCS 问题就是要求出A 和B 的LCS。</li><li>定义4 给定字符串A=A[1]A[2]&#8230;A[m]和字符串B=B[1]B[2]&#8230;[n]，A( 1:i)表示A 的连续子序列A[1]A[2]&#8230;A[i]，同样B(1:j)表示B 的连续子序列B[1]B[2]&#8230;[j]。Li(k)表示所有与字符串A(1:i) 有长度为k 的LCS 的字符串B(l:j) 中j 的最小值。用公式表示就是Li(k)=Minj(LCS(A(1:i)，B(l:j))=k) [3]。<br /><br /><br style="color: #333333; background-color: #ffffff;" /><span style="color: #333333; background-color: #ffffff;">定理1 &#8704; i&#8712;[1，m]，有Li(l)&lt;Li(2)&lt;Li(3)&lt;&#8230;&lt;Li(m) .</span><br style="color: #333333; background-color: #ffffff;" /><span style="color: #333333; background-color: #ffffff;">定理2 &#8704;i&#8712;[l，m-1]，&#8704;k&#8712;[l，m]，有i 1 L + (k)&lt;= i L (k).</span><br style="color: #333333; background-color: #ffffff;" /><span style="color: #333333; background-color: #ffffff;">定理3 &#8704; i&#8712;[l，m-1]， &#8704; k&#8712;[l，m-l]，有i L (k)&lt; i 1 L + (k+l).</span><br style="color: #333333; background-color: #ffffff;" /><span style="color: #333333; background-color: #ffffff;">以上三个定理都不考虑Li(k)无定义的情况。</span><br style="color: #333333; background-color: #ffffff;" /><span style="color: #333333; background-color: #ffffff;">定理4[3] i 1 L + (k)如果存在，那么它的取值必为: i 1 L + (k)=Min(j, i L (k))。这里j 是满足以下条件的最小整数:A[i+l]=B[j]且j&gt; i L (k-1)。<br /><br /></span><img src="http://www.cppblog.com/images/cppblog_com/mysileng/QQ截图20130514220338.jpg" width="620" height="327" alt="" /><br /><p dir="ltr" style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff; margin-right: 0px;">&nbsp;矩阵中元素L(k，i)=Li(k)，这里(1&lt;i&lt;=m，1&lt;k&lt;=m)，null 表示L(k,i)不存在。当i&lt;k 时，显然L(k，i)不存在。<br />&nbsp;&nbsp;&nbsp; 设p=Maxk(L(k ， m) &#8800; null) ， 可以证明L 矩阵中L(p,m) 所在的对角线,L(1,m-p+1),L(2,m-p+2)&#8230;L(p-1,m-1),L(p,m) 所对应的子序列B[L(1,m-p+1)]B[L(2,m-p+2)]&#8230;B[L(p,m)]即为A 和B 的LCS，p 为该LCS 的长度。这样，LCS 问题的求解就转化为对m m L &#215; 矩阵的求解。<br /><br /><strong style="font-size: 14px;">6.2 算法思想</strong></p><p dir="ltr" style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff; margin-right: 0px;">&nbsp;&nbsp;&nbsp; 根据定理,第一步求出第一行元素,L(1,1),L(1,2),&#8230;L(1,m),第二步求第二行,一直到发现第p+1 行都为null 为止。在计算过程中遇到i&lt;k 时,L(k,i)=null, 及L(k,i)=k时,L(k,i+1)=L(k,i+2)=&#8230;L(k,m)=k。这样,计算每行的时间复杂度为O(n),则整个时间复杂度为O(pn)。在求L 矩阵的过程中不用存储整个矩阵,只需存储当前行和上一行即可。空间复杂度为O(m+n)。</p><p dir="ltr" style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff; margin-right: 0px;">&nbsp;&nbsp;&nbsp; 下面给出一个例子来说明:给定字符串A 和B，A=acdabbc，B=cddbacaba，(m= A =7，n= B =9)。按照定理给出的递推公式，求出A 和B 的L 矩阵如图2，其中的$表示NULL。<br /><img src="http://www.cppblog.com/images/cppblog_com/mysileng/QQ截图20130514220446.jpg" width="610" height="375" alt="" /><br /><p dir="ltr" style="font-size: 14px; margin-right: 0px;">则A 和B 的LCS 为B[1]B[2]B[4]B[6]=cdbc,LCS 的长度为4。</p><p dir="ltr" style="font-size: 14px; margin-right: 0px;"><strong>6.3 算法伪代码<br /></strong>算法 L(A,B,L)<br />输入 长度分别为m,n 的字符串A,B<br />输出 A,B 的最长公共子序列LCS</p><div bg_cpp"="" style="border: 1px dashed #999999; background-color: #f5f5f5; width: 687.0499877929688px;"><ol start="1" style="margin-bottom: 0px; margin-left: 0px; padding-top: 5px; padding-bottom: 5px; position: relative;"><li style="border-left-style: none; line-height: 13px;">L(A,B,L){<span style="color: #999999;">//字符串A，B，所求矩阵L</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;<span style="color: #0000ff;">for</span>(k=1;k&lt;=m;k++){&nbsp;<span style="color: #999999;">//m&nbsp;为A&nbsp;的长度</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>(i=1;i&lt;=m;i++){&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(i&lt;k)&nbsp;L[k][i]=N;<span style="color: #999999;">//i&lt;k&nbsp;时,L(k,i)=null，N&nbsp;代表无穷大</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(L[k][i]==k)<span style="color: #999999;">//L(k,i)=k&nbsp;时,L(k,i+1)=L(k,i+2)=&#8230;L(k,m)=k</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>(l=i+1;l&lt;=m;l++)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;L[k][l]=k;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Break;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>(j=1;j&lt;=n;j++){<span style="color: #999999;">//定理4&nbsp;的实现</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(A[i+1]==B[j]&amp;&amp;j&gt;L[k-1][i]){&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;L[k][i+1]=(j&lt;L[k][i]?j:L[k][i]);&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">break</span>;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(L[k][i+1]==0)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;L[k][i]=N;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(L[k][m]==N)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{p=k-1;<span style="color: #0000ff;">break</span>;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;p=k-1;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">}&nbsp;&nbsp;</li></ol></div><p dir="ltr" style="font-size: 14px;"><strong>6.4 结语<br /></strong>&nbsp;&nbsp;&nbsp; 本节主要描述区别于动态规划法的一种新的求解最长公共子序列问题的方法，在不影响精确度的前提下，提高序列匹配的速度，根据定理i 1 L + (k)=Min(j, i L (k))得出矩阵，在求解矩阵的过程中对最耗时的L(p,m)进行条件约束优化。我们在Intel(R) Core(TM)2 Quad 双核处理器、1G 内存，软件环境：windows xp 下试验结果证明，本文算法与其他经典的比对算法相比,不但能够取得准确的结果,而且速度有了较大的提高（本节参考了刘佳梅女士的论文）。</p><p style="font-size: 14px;">&nbsp;&nbsp;&nbsp; 若有任何问题，恳请不吝指正。谢谢各位。完。</p><br /><br /></p></li></ul><p>&nbsp;</p><img src ="http://www.cppblog.com/mysileng/aggbug/200265.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2013-05-14 22:05 <a href="http://www.cppblog.com/mysileng/archive/2013/05/14/200265.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序员编程艺术-----第九章-----闲话链表追赶问题</title><link>http://www.cppblog.com/mysileng/archive/2013/05/14/200264.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Tue, 14 May 2013 13:35:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2013/05/14/200264.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/200264.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2013/05/14/200264.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/200264.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/200264.html</trackback:ping><description><![CDATA[<p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">作者：July、狂想曲创作组。<br />出处：<a href="http://blog.csdn.net/v_JULY_v" target="_blank" style="color: #336699; text-decoration: initial;"><strong><span style="color: #002d93;">http://blog.csdn.net/v_JULY_v</span>&nbsp;</strong></a>。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><br /><span style="font-size: 16px;"><span style="color: #800000;">前奏</span></span><br />&nbsp;&nbsp;&nbsp;&nbsp;<strong>有这样一个问题：</strong>在一条左右水平放置的直线轨道上任选两个点，放置两个机器人，请用如下指令系统为机器人设计控制程序，使这两个机器人能够在直线轨道上相遇。（注意两个机器人用你写的同一个程序来控制）。<br />&nbsp;&nbsp;&nbsp; 指令系统：只包含4条指令，向左、向右、条件判定、无条件跳转。其中向左（右）指令每次能控制机器人向左（右）移动一步；条件判定指令能对机器人所在的位置进行条件测试，测试结果是如果对方机器人曾经到过这里就返回true，否则返回false；无条件跳转，类似汇编里面的跳转，可以跳转到任何地方。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; ok，这道很有意思的趣味题是去年微软工程院的题，文末将给出解答（如果急切想知道此问题的答案，可以直接跳到本文第三节）。同时，我们看到其实这个题是一个典型的追赶问题，那么追赶问题在哪种面试题中比较常见?对了，链表追赶。本章就来阐述这个问题。有不正之处，望不吝指正。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><br /><span style="color: #800000;"><span style="font-size: 16px;">第一节、求链表倒数第k个结点</span></span><br /><strong>第13题、题目描述：</strong><br />输入一个单向链表，输出该链表中倒数第k个结点,<br />链表的倒数第0个结点为链表的尾指针。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><strong>分析：</strong>此题一出，相信，稍微有点 经验的同志，都会说到：设置两个指针p1,p2，首先p1和p2都指向head，然后p2向前走k步，这样p1和p2之间就间隔k个节点，最后p1和p2同时向前移动，直至p2走到链表末尾。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 前几日有朋友提醒我说，让我讲一下此种求链表倒数第k个结点的问题。我想，这种问题，有点经验的人恐怕都已了解过，无非是利用两个指针一前一后逐步前移。但他提醒我说，如果参加面试的人没有这个意识，它怎么也想不到那里去。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 那在平时准备面试的过程中如何加强这一方面的意识呢?我想，除了平时遇到一道面试题，尽可能用多种思路解决，以延伸自己的视野之外，便是平时有意注意观察生活。因为，相信，你很容易了解到，其实这种链表追赶的问题来源于生活中长跑比赛，如果平时注意多多思考，多多积累，多多发现并体味生活，相信也会对面试有所帮助。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; ok，扯多了，下面给出这个题目的主体代码，如下：</p><blockquote style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><p>struct ListNode<br />{<br />&nbsp;&nbsp;&nbsp; char data;<br />&nbsp;&nbsp;&nbsp; ListNode* next;<br />};<br />ListNode* head,*p,*q;<br />ListNode *pone,*ptwo;</p><p><a style="color: #336699;">//@heyaming</a>, 第一节,求链表倒数第k个结点应该考虑k大于链表长度的case。<br />ListNode* fun(ListNode *head,int k)<br />{<br />&nbsp;assert(k &gt;= 0);<br />&nbsp;pone = ptwo = head;<br />&nbsp;for( ; k &gt; 0 &amp;&amp; ptwo != NULL; k--)<br />&nbsp;&nbsp;ptwo=ptwo-&gt;next;<br />&nbsp;if (k &gt; 0) return NULL;<br />&nbsp;<br />&nbsp;while(ptwo!=NULL)<br />&nbsp;{<br />&nbsp;&nbsp;pone=pone-&gt;next;<br />&nbsp;&nbsp;ptwo=ptwo-&gt;next;<br />&nbsp;}<br />&nbsp;return pone;<br />}&nbsp;</p><p>&nbsp;</p></blockquote><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><strong>扩展：</strong><br />这是针对链表单项链表查找其中倒数第k个结点。试问，如果链表是双向的，且可能存在环呢?请看第二节、编程判断两个链表是否相交。<br /></p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><br /><span style="font-size: 16px;"><span style="color: #800000;">第二节、编程判断两个链表是否相交</span></span><br /><strong>题目描述</strong>：给出两个单向链表的头指针（如下图所示）<br /><img src="http://www.cppblog.com/images/cppblog_com/mysileng/QQ截图20130514213339.jpg" width="466" height="133" alt="" /><br /><p style="font-size: 14px;">比如h1、h2，判断这两个链表是否相交。这里为了简化问题，我们假设两个链表均不带环。</p><p style="font-size: 14px;"><strong>分析：</strong>这是来自编程之美上的微软亚院的一道面试题目。请跟着我的思路步步深入（部分文字引自编程之美）：</p><ol style="font-size: 14px;"><li>直接循环判断第一个链表的每个节点是否在第二个链表中。但，这种方法的时间复杂度为O(Length(h1) * Length(h2))。显然，我们得找到一种更为有效的方法，至少不能是O（N^2）的复杂度。</li><li>针对第一个链表直接构造hash表，然后查询hash表，判断第二个链表的每个结点是否在hash表出现，如果所有的第二个链表的结点都能在hash表中找到，即说明第二个链表与第一个链表有相同的结点。时间复杂度为为线性：O(Length(h1) + Length(h2))，同时为了存储第一个链表的所有节点，空间复杂度为O(Length(h1))。是否还有更好的方法呢，既能够以线性时间复杂度解决问题，又能减少存储空间？</li><li>进一步考虑&#8220;如果两个没有环的链表相交于某一节点，那么在这个节点之后的所有节点都是两个链表共有的&#8221;这个特点，我们可以知道，如果它们相交，则最后一个节点一定是共有的。而我们很容易能得到链表的最后一个节点，所以这成了我们简化解法的一个主要突破口。那么，我们只要判断俩个链表的尾指针是否相等。相等，则链表相交；否则，链表不相交。<br />所以，先遍历第一个链表，记住最后一个节点。然后遍历第二个链表，到最后一个节点时和第一个链表的最后一个节点做比较，如果相同，则相交，否则，不相交。这样我们就得到了一个时间复杂度，它为O((Length(h1) + Length(h2))，而且只用了一个额外的指针来存储最后一个节点。这个方法时间复杂度为线性O（N），空间复杂度为O（1），显然比解法三更胜一筹。</li><li>上面的问题都是针对链表无环的，<strong>那么如果现在，链表是有环的呢?</strong>还能找到最后一个结点进行判断么?上面的方法还同样有效么?显然，这个问题的本质已经转化为判断链表是否有环。那么，如何来判断链表是否有环呢?</li></ol><p style="font-size: 14px;"><strong>总结：</strong><br />所以，事实上，这个判断两个链表是否相交的问题就转化成了：<br />1.先判断带不带环<br />2.如果都不带环，就判断尾节点是否相等<br />3.如果都带环，判断一链表上俩指针相遇的那个节点，在不在另一条链表上。<br />如果在，则相交，如果不在，则不相交。</p><p style="font-size: 14px;">&nbsp;&nbsp;&nbsp;&nbsp;<strong>1、</strong>那么，如何编写代码来判断链表是否有环呢?因为很多的时候，你给出了问题的思路后，面试官可能还要追加你的代码，ok，如下（设置两个指针(p1, p2)，初始值都指向头，p1每次前进一步，p2每次前进二步，如果链表存在环，则p2先进入环，p1后进入环，两个指针在环中走动，必定相遇）：</p><blockquote style="font-size: 14px; background-color: #ffffff;"><p>&nbsp;</p><div bg_cpp"="" style="border: 1px dashed #999999; background-color: #f5f5f5; width: 607.8499755859375px;"><ol start="1" style="margin-bottom: 0px; margin-left: 0px; padding-top: 5px; padding-bottom: 5px; position: relative;"><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//copyright@&nbsp;KurtWang</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//July、2011.05.27。</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #0000ff;">struct</span>&nbsp;Node&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;value;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;Node&nbsp;*&nbsp;next;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">};&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//1.先判断带不带环</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//判断是否有环，返回bool，如果有环，返回环里的节点</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//思路：用两个指针，一个指针步长为1，一个指针步长为2，判断链表是否有环</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #2e8b57; font-weight: bold;">bool</span>&nbsp;isCircle(Node&nbsp;*&nbsp;head,&nbsp;Node&nbsp;*&amp;&nbsp;circleNode,&nbsp;Node&nbsp;*&amp;&nbsp;lastNode)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;Node&nbsp;*&nbsp;fast&nbsp;=&nbsp;head-&gt;next;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;Node&nbsp;*&nbsp;slow&nbsp;=&nbsp;head;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">while</span>(fast&nbsp;!=&nbsp;slow&nbsp;&amp;&amp;&nbsp;fast&nbsp;&amp;&amp;&nbsp;slow)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(fast-&gt;next&nbsp;!=&nbsp;NULL)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fast&nbsp;=&nbsp;fast-&gt;next;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(fast-&gt;next&nbsp;==&nbsp;NULL)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lastNode&nbsp;=&nbsp;fast;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(slow-&gt;next&nbsp;==&nbsp;NULL)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lastNode&nbsp;=&nbsp;slow;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fast&nbsp;=&nbsp;fast-&gt;next;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;slow&nbsp;=&nbsp;slow-&gt;next;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(fast&nbsp;==&nbsp;slow&nbsp;&amp;&amp;&nbsp;fast&nbsp;&amp;&amp;&nbsp;slow)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;circleNode&nbsp;=&nbsp;fast;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;<span style="color: #0000ff;">true</span>;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">else</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;<span style="color: #0000ff;">false</span>;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">}&nbsp;&nbsp;</li></ol></div><p>&nbsp;</p></blockquote><p style="font-size: 14px;">&nbsp;&nbsp;&nbsp;&nbsp;<strong>2&amp;3、</strong>如果都不带环，就判断尾节点是否相等，如果都带环，判断一链表上俩指针相遇的那个节点，在不在另一条链表上。下面是综合解决这个问题的代码：</p><blockquote style="font-size: 14px; background-color: #ffffff;"><p>&nbsp;</p><div bg_cpp"="" style="border: 1px dashed #999999; background-color: #f5f5f5; width: 607.8499755859375px;"><ol start="1" style="margin-bottom: 0px; margin-left: 0px; padding-top: 5px; padding-bottom: 5px; position: relative;"><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//判断带环不带环时链表是否相交</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//2.如果都不带环，就判断尾节点是否相等</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//3.如果都带环，判断一链表上俩指针相遇的那个节点，在不在另一条链表上。</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #2e8b57; font-weight: bold;">bool</span>&nbsp;detect(Node&nbsp;*&nbsp;head1,&nbsp;Node&nbsp;*&nbsp;head2)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;Node&nbsp;*&nbsp;circleNode1;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;Node&nbsp;*&nbsp;circleNode2;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;Node&nbsp;*&nbsp;lastNode1;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;Node&nbsp;*&nbsp;lastNode2;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">bool</span>&nbsp;isCircle1&nbsp;=&nbsp;isCircle(head1,circleNode1,&nbsp;lastNode1);&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">bool</span>&nbsp;isCircle2&nbsp;=&nbsp;isCircle(head2,circleNode2,&nbsp;lastNode2);&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//一个有环，一个无环</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(isCircle1&nbsp;!=&nbsp;isCircle2)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;<span style="color: #0000ff;">false</span>;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//两个都无环，判断最后一个节点是否相等</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">else</span>&nbsp;<span style="color: #0000ff;">if</span>(!isCircle1&nbsp;&amp;&amp;&nbsp;!isCircle2)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;lastNode1&nbsp;==&nbsp;lastNode2;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//两个都有环，判断环里的节点是否能到达另一个链表环里的节点</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">else</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Node&nbsp;*&nbsp;temp&nbsp;=&nbsp;circleNode1-&gt;next;&nbsp;&nbsp;<span style="color: #999999;">//updated，多谢苍狼&nbsp;and&nbsp;hyy。</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">while</span>(temp&nbsp;!=&nbsp;circleNode1)&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(temp&nbsp;==&nbsp;circleNode2)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;<span style="color: #0000ff;">true</span>;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp&nbsp;=&nbsp;temp-&gt;next;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;<span style="color: #0000ff;">false</span>;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;<span style="color: #0000ff;">false</span>;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">}&nbsp;&nbsp;</li></ol></div><p>&nbsp;</p></blockquote><p style="font-size: 14px;"><strong>扩展2：求两个链表相交的第一个节点</strong><br />思路：在判断是否相交的过程中要分别遍历两个链表，同时记录下各自长度。</p><p style="font-size: 14px;">&nbsp;&nbsp;&nbsp; @Joshua：这个算法需要处理一种特殊情况，即：其中一个链表的头结点在另一个链表的环中，且不是环入口结点。这种情况有两种意思：1)如果其中一个链表是循环链表，则另一个链表必为循环链表，即两个链表重合但头结点不同；2)如果其中一个链表存在环(除去循环链表这种情况)，则另一个链表必在此环中与此环重合，其头结点为环中的一个结点，但不是入口结点。在这种情况下我们约定，如果链表B的头结点在链表A的环中，且不是环入口结点，那么链表B的头结点即作为A和B的第一个相交结点；如果A和B重合(定义方法时形参A在B之前)，则取B的头结点作为A和B的第一个相交结点。&nbsp;</p><div style="font-size: 14px;">&nbsp; &nbsp; @风过无痕：读《程序员编程艺术》，补充代码2012年7月18日&nbsp;周三下午10:15<br />&nbsp; &nbsp; 发件人:&nbsp;"風過無痕"&nbsp;&lt;luxiaoxun001@qq.com&gt;将发件人添加到联系人<br />&nbsp; &nbsp; 收件人:&nbsp;"zhoulei0907"&nbsp;&lt;zhoulei0907@yahoo.cn&gt;<br />你好<br />&nbsp;&nbsp;&nbsp;&nbsp;看到你在csdn上博客，学习了很多，看到下面一章，有个扩展问题没有代码，发现自己有个，发给你吧，思路和别人提出来的一样，感觉有代码更加完善一些，呵呵<br /><br />扩展2：求两个链表相交的第一个节点<br />&nbsp; &nbsp; 思路：如果两个尾结点是一样的，说明它们有重合；否则两个链表没有公共的结点。<br />&nbsp; &nbsp; 在上面的思路中，顺序遍历两个链表到尾结点的时候，我们不能保证在两个链表上同时到达尾结点。这是因为两个链表不一定长度一样。但如果假设一个链表比另一个长L个结点，我们先在长的链表上遍历L个结点，之后再同步遍历，这个时候我们就能保证同时到达最后一个结点了。由于两个链表从第一个公共结点开始到链表的尾结点，这一部分是重合的。因此，它们肯定也是同时到达第一公共结点的。于是在遍历中，第一个相同的结点就是第一个公共的结点。<br />&nbsp; &nbsp; 在这个思路中，我们先要分别遍历两个链表得到它们的长度，并求出两个长度之差。在长的链表上先遍历若干次之后，再同步遍历两个链表，直到找到相同的结点，或者一直到链表结束。PS：没有处理一种特殊情况：就是一个是循环链表，而另一个也是，只是头结点所在位置不一样。&nbsp;</div><p style="font-size: 14px;">&nbsp; &nbsp; 代码如下：</p><p style="font-size: 14px;"></p><div bg_cpp"="" style="border: 1px dashed #999999; background-color: #f5f5f5; width: 687.0499877929688px;"><ol start="1" style="margin-bottom: 0px; margin-left: 0px; padding-top: 5px; padding-bottom: 5px; position: relative;"><li style="border-left-style: none; line-height: 13px;">ListNode*&nbsp;FindFirstCommonNode(&nbsp;ListNode&nbsp;*pHead1,&nbsp;ListNode&nbsp;*pHead2)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//&nbsp;Get&nbsp;the&nbsp;length&nbsp;of&nbsp;two&nbsp;lists</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;nLength1&nbsp;=&nbsp;ListLength(pHead1);&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;nLength2&nbsp;=&nbsp;ListLength(pHead2);&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;nLengthDif&nbsp;=&nbsp;nLength1&nbsp;-&nbsp;nLength2;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//&nbsp;Get&nbsp;the&nbsp;longer&nbsp;list</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ListNode&nbsp;*pListHeadLong&nbsp;=&nbsp;pHead1;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ListNode&nbsp;*pListHeadShort&nbsp;=&nbsp;pHead2;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(nLength2&nbsp;&gt;&nbsp;nLength1)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pListHeadLong&nbsp;=&nbsp;pHead2;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pListHeadShort&nbsp;=&nbsp;pHead1;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nLengthDif&nbsp;=&nbsp;nLength2&nbsp;-&nbsp;nLength1;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//&nbsp;Move&nbsp;on&nbsp;the&nbsp;longer&nbsp;list</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>(<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;nLengthDif;&nbsp;++&nbsp;i)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pListHeadLong&nbsp;=&nbsp;pListHeadLong-&gt;m_pNext;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//&nbsp;Move&nbsp;on&nbsp;both&nbsp;lists</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">while</span>((pListHeadLong&nbsp;!=&nbsp;NULL)&nbsp;&amp;&amp;&nbsp;(pListHeadShort&nbsp;!=&nbsp;NULL)&nbsp;&amp;&amp;&nbsp;(pListHeadLong&nbsp;!=&nbsp;pListHeadShort))&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pListHeadLong&nbsp;=&nbsp;pListHeadLong-&gt;m_pNext;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pListHeadShort&nbsp;=&nbsp;pListHeadShort-&gt;m_pNext;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//&nbsp;Get&nbsp;the&nbsp;first&nbsp;common&nbsp;node&nbsp;in&nbsp;two&nbsp;lists</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ListNode&nbsp;*pFisrtCommonNode&nbsp;=&nbsp;NULL;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(pListHeadLong&nbsp;==&nbsp;pListHeadShort)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pFisrtCommonNode&nbsp;=&nbsp;pListHeadLong;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;pFisrtCommonNode;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">unsigned&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;ListLength(ListNode*&nbsp;pHead)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;nLength&nbsp;=&nbsp;0;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ListNode*&nbsp;pNode&nbsp;=&nbsp;pHead;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">while</span>(pNode&nbsp;!=&nbsp;NULL)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;++&nbsp;nLength;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pNode&nbsp;=&nbsp;pNode-&gt;m_pNext;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;nLength;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">}&nbsp;&nbsp;</li></ol></div><p style="font-size: 14px;"></p><p style="font-size: 14px;">&nbsp; &nbsp; 关于判断单链表是否相交的问题，还可以看看此篇文章：<a href="http://www.cppblog.com/humanchao/archive/2008/04/17/47357.html" target="_blank" style="color: #336699; text-decoration: initial;"><span style="font-family: 'Comic Sans MS';">http://www.cppblog.com/humanchao/archive/2008/04/17/47357.html</span></a>。ok，下面，回到本章前奏部分的那道非常有趣味的智力题。</p><p style="font-size: 14px;"><br /></p><p style="font-size: 14px;"><span style="color: #800000;"><span style="font-size: 16px;">第三节、微软工程院面试智力题</span></span><br /><strong>题目描述：</strong><br />&nbsp;&nbsp;&nbsp; 在一条左右水平放置的直线轨道上任选两个点，放置两个机器人，请用如下指令系统为机器人设计控制程序，使这两个机器人能够在直线轨道上相遇。（注意两个机器人用你写的同一个程序来控制）<br />&nbsp;&nbsp;&nbsp; 指令系统：只包含4条指令，向左、向右、条件判定、无条件跳转。其中向左（右）指令每次能控制机器人向左（右）移动一步；条件判定指令能对机器人所在的位置进行条件测试，测试结果是如果对方机器人曾经到过这里就返回true，否则返回false；无条件跳转，类似汇编里面的跳转，可以跳转到任何地方。</p><p style="font-size: 14px;"><strong>分析：</strong>我尽量以最清晰的方式来说明这个问题（大部分内容来自ivan，big等人的讨论）：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>&nbsp;1、</strong>首先题目要求很简单，就是要你想办法让A最终能赶上B，A在后，B在前，都向右移动，如果它们的速度永远一致，那A是永远无法追赶上B的。但题目给出了一个条件判断指令，即如果A或B某个机器人向前移动时，若是某个机器人经过的点是第二个机器人曾经经过的点，那么程序返回true。对的，就是抓住这一点，A到达曾经B经过的点后，发现此后的路是B此前经过的，那么A开始提速两倍，B一直保持原来的一倍速度不变，那样的话，A势必会在|AB|/move_right个单位时间内，追上B。ok，简单伪代码如下：</p><p style="font-size: 14px; padding-left: 30px;">start:<br />if(at the position other robots have not reached)<br />&nbsp;&nbsp;&nbsp; move_right<br />if(at the position other robots have reached)<br />&nbsp;&nbsp;&nbsp; move_right<br />&nbsp;&nbsp;&nbsp; move_right<br />goto start</p><p style="font-size: 14px;">再简单解释下上面的伪代码（@big）：<br />A------------B<br />|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br />在A到达B点前，两者都只有第一条if为真，即以相同的速度向右移动，在A到达B后，A只满足第二个if，即以两倍的速度向右移动，B依然只满足第一个if，则速度保持不变，经过|AB|/move_right个单位时间，A就可以追上B。</p><p style="font-size: 14px;">&nbsp;</p><p style="font-size: 14px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>2、</strong>有个细节又出现了，正如ivan所说，</p><p style="font-size: 14px; padding-left: 30px;">if(at the position other robots have reached)<br />&nbsp;&nbsp;&nbsp; move_right<br />&nbsp;&nbsp;&nbsp; move_right</p><p style="font-size: 14px;">上面这个分支不一定能提速的。why?因为如果if条件花的时间很少，而move指令发的时间很大（实际很可能是这样），那么两个机器人的速度还是基本是一样的。</p><p style="font-size: 14px;">那作如何修改呢?:</p><p style="font-size: 14px; padding-left: 30px;">start:<br />if(at the position other robots have not reached)<br />&nbsp;&nbsp;&nbsp; move_right<br />&nbsp;&nbsp;&nbsp; move_left<br />&nbsp;&nbsp;&nbsp; move_right<br />if(at the position other robots have reached)<br />&nbsp;&nbsp;&nbsp; move_right<br />goto start</p><p style="font-size: 14px; padding-left: 30px;">-------</p><p style="font-size: 14px;">这样改后，A的速度应该比B快了。</p><p style="font-size: 14px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>&nbsp;3、</strong>然要是说每个指令处理速度都很快，AB岂不是一直以相同的速度右移了?那到底该作何修改呢?请看：</p><p style="font-size: 14px; padding-left: 30px;">go_step()<br />{<br />&nbsp;&nbsp; 向右<br />&nbsp;&nbsp; 向左<br />&nbsp;&nbsp; 向右<br />}<br />--------<br />三个时间单位才向右一步</p><p style="font-size: 14px; padding-left: 30px;">go_2step()<br />{<br />&nbsp;&nbsp; 向右<br />}<br />------</p><p style="font-size: 14px;">&nbsp;&nbsp;&nbsp; 一个时间单向右一步向左和向右花的时间是同样的，并且会占用一定时间。 如果条件判定指令时间比移令花的时间较少的话，应该上面两种步法，后者比前者快。至此，咱们的问题已经得到解决。</p></p><img src ="http://www.cppblog.com/mysileng/aggbug/200264.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2013-05-14 21:35 <a href="http://www.cppblog.com/mysileng/archive/2013/05/14/200264.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序员编程艺术-----第八章-----从头至尾漫谈虚函数</title><link>http://www.cppblog.com/mysileng/archive/2013/05/13/200230.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Mon, 13 May 2013 10:51:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2013/05/13/200230.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/200230.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2013/05/13/200230.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/200230.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/200230.html</trackback:ping><description><![CDATA[<p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">作者：July。<br />出处：<a href="http://blog.csdn.net/v_JULY_v" target="_blank" style="color: #336699; text-decoration: initial;"><strong><span style="color: #002d93;">http://blog.csdn.net/v_JULY_v</span>&nbsp;</strong></a>。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><span style="color: #800000;"><span style="font-size: 16px;">前奏</span></span></p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 有关虚函数的问题层出不穷，有关虚函数的文章千篇一律，那为何还要写这一篇有关虚函数的文章呢?看完本文后，相信能懂其意义之所在。同时，原<span style="text-decoration: line-through;">狂想曲系列</span>已经更名为<span style="text-decoration: underline;"><strong>程序员编程艺术系列</strong></span>，因为不再只专注于&#8220;面试&#8221;，而在&#8220;编程&#8221;之上了。ok，如果有不正之处，望不吝赐教。谢谢。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><br /><span style="font-size: 16px;"><span style="color: #800000;">第一节、一道简单的虚函数的面试题</span></span><br />题目要求：写出下面程序的运行结果?<br /></p><div bg_cpp"="" style="border: 1px dashed #999999; background-color: #f5f5f5; width: 687.0499877929688px;"><ol start="1" style="margin-bottom: 0px; margin-left: 0px; padding-top: 5px; padding-bottom: 5px; position: relative;"><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//谢谢董天喆提供的这道百度的面试题&nbsp;</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">#include&nbsp;&lt;iostream&gt;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #0000ff;">using</span>&nbsp;<span style="color: #0000ff;">namespace</span>&nbsp;std;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #0000ff;">class</span>&nbsp;A{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;<span style="color: #0000ff;">public</span>:<span style="color: #0000ff;">virtual</span>&nbsp;<span style="color: #0000ff;">void</span>&nbsp;p()&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;<span style="color: #009900;">"A"</span>&nbsp;&lt;&lt;&nbsp;endl;&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">};&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #0000ff;">class</span>&nbsp;B&nbsp;:&nbsp;<span style="color: #0000ff;">public</span>&nbsp;A&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;<span style="color: #0000ff;">public</span>:<span style="color: #0000ff;">virtual</span>&nbsp;<span style="color: #0000ff;">void</span>&nbsp;p()&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;{&nbsp;cout&nbsp;&lt;&lt;&nbsp;<span style="color: #009900;">"B"</span>&nbsp;&lt;&lt;&nbsp;endl;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">};&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;main()&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;A&nbsp;*&nbsp;a&nbsp;=&nbsp;<span style="color: #0000ff;">new</span>&nbsp;A;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;A&nbsp;*&nbsp;b&nbsp;=&nbsp;<span style="color: #0000ff;">new</span>&nbsp;B;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;a-&gt;p();&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;b-&gt;p();&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;<span style="color: #0000ff;">delete</span>&nbsp;a;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;<span style="color: #0000ff;">delete</span>&nbsp;b;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;0;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">}&nbsp;&nbsp;</li></ol></div><p>&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 我想，这道面试题应该是考察虚函数相关知识的相对简单的一道题目了。然后，希望你碰到此类有关虚函数的面试题，不论其难度是难是易，都能够举一反三，那么本章的目的也就达到了。ok，请跟着我的思路，咱们步步深入（上面程序的输出结果为A B）。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><span style="font-size: 16px;"><span style="color: #800000;">第二节、有无虚函数的区别</span></span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>1、</strong>当上述程序中的函数p()不是虚函数，那么程序的运行结果是如何?即如下代码所示：</p><blockquote style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><p>class A<br />{<br />public:<br />&nbsp;void p()&nbsp;<br />&nbsp;{&nbsp;<br />&nbsp;&nbsp;cout &lt;&lt; "A" &lt;&lt; endl;&nbsp;<br />&nbsp;}<br />&nbsp;<br />};</p><p>class B : public A<br />{<br />public:<br />&nbsp;void p()&nbsp;<br />&nbsp;{&nbsp;<br />&nbsp;&nbsp;cout &lt;&lt; "B" &lt;&lt; endl;<br />&nbsp;}<br />};</p></blockquote><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">对的，程序此时将输出两个A，A。为什么?<br />我们知道，在构造一个类的对象时，如果它有基类，那么首先将构造基类的对象，然后才构造派生类自己的对象。如上，A* a=new A，调用默认构造函数构造基类A对象，然后调用函数p()，a-&gt;p();输出A，这点没有问题。<br />&nbsp;&nbsp;&nbsp; 然后，A * b = new B;，构造了派生类对象B，B由于是基类A的派生类对象，所以会先构造基类A对象，然后再构造派生类对象，但由于当程序中函数是非虚函数调用时，B类对象对函数p()的调用时在编译时就已静态确定了，所以，不论基类指针b最终指向的是基类对象还是派生类对象，只要后面的对象调用的函数不是虚函数，那么就直接无视，而调用基类A的p()函数。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>2、</strong>那如果加上虚函数呢?即如最开始的那段程序那样，程序的输出结果，将是什么?<br />在此之前，我们还得明确以下两点：<br />&nbsp;&nbsp;&nbsp; a、通过基类引用或指针调用基类中定义的函数时，我们并不知道执行函数的对象的确切类型，执行函数的对象可能是基类类型的，也可能是派生类型的。<br />&nbsp;&nbsp;&nbsp; b、如果调用非虚函数，则无论实际对象是什么类型，都执行基类类型所定义的函数（如上述第1点所述）。如果调用虚函数，则直到运行时才能确定调用哪个函数，运行的虚函数是引用所绑定的或指针所指向的对象所属类型定义的版本。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">根据上述b的观点，我们知道，如果加上虚函数，如上面这道面试题，</p><blockquote style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><p>class A<br />{<br />public:<br />&nbsp;virtual void p()&nbsp;<br />&nbsp;{&nbsp;<br />&nbsp;&nbsp;cout &lt;&lt; "A" &lt;&lt; endl;&nbsp;<br />&nbsp;}<br />&nbsp;<br />};</p><p>class B : public A<br />{<br />public:<br />&nbsp;virtual void p()&nbsp;<br />&nbsp;{&nbsp;<br />&nbsp;&nbsp;cout &lt;&lt; "B" &lt;&lt; endl;<br />&nbsp;}<br />};</p><p>int main()&nbsp;<br />{<br />&nbsp;A * a = new A;<br />&nbsp;A * b = new B;<br />&nbsp;a-&gt;p();<br />&nbsp;b-&gt;p();<br />&nbsp;delete a;<br />&nbsp;delete b;<br />&nbsp;&nbsp;&nbsp; return 0;<br />}</p><p>&nbsp;</p></blockquote><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">那么程序的输出结果将是A B。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">所以，至此，咱们的这道面试题已经解决。但虚函数的问题，还没有解决。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><br /><span style="color: #800000;"><span style="font-size: 16px;">第三节、虚函数的原理与本质</span></span><br />&nbsp;&nbsp;&nbsp; 我们已经知道，虚（virtual）函数的一般实现模型是：每一个类（class）有一个虚表（virtual table），内含该class之中有作用的虚（virtual）函数的地址，然后每个对象有一个vptr，指向虚表（virtual table）的所在。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">请允许我援引自深度探索c++对象模型一书上的一个例子：</p><blockquote style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><p>class Point {&nbsp;<br />public:&nbsp;<br />&nbsp;&nbsp; virtual ~Point();&nbsp;&nbsp;</p><p>&nbsp;&nbsp; virtual Point&amp; mult( float ) = 0;&nbsp;</p><p>&nbsp;&nbsp; float x() const { return _x; }&nbsp;&nbsp;&nbsp;&nbsp; //非虚函数，不作存储<br />&nbsp;&nbsp; virtual float y() const { return 0; }&nbsp;&nbsp;<br />&nbsp;&nbsp; virtual float z() const { return 0; }&nbsp;&nbsp;<br />&nbsp;&nbsp; // ...</p><p>protected:&nbsp;<br />&nbsp;&nbsp; Point( float x = 0.0 );&nbsp;<br />&nbsp;&nbsp; float _x;&nbsp;<br />};</p></blockquote><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>1、</strong>在Point的对象pt中，有两个东西，一个是数据成员_x，一个是_vptr_Point。其中_vptr_Point指向着virtual table point，而virtual table（虚表）point中存储着以下东西：</p><ul style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><li>virtual ~Point()被赋值slot 1，</li><li>mult() 将被赋值slot 2.</li><li>y() is 将被赋值slot 3</li><li>z() 将被赋值slot 4.</li></ul><blockquote style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><p>class Point2d : public Point {&nbsp;<br />public:&nbsp;<br />&nbsp;&nbsp; Point2d( float x = 0.0, float y = 0.0 )&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : Point( x ), _y( y ) {}&nbsp;<br />&nbsp;&nbsp; ~Point2d();&nbsp;&nbsp; //1</p><p>&nbsp;&nbsp; //改写base class virtual functions&nbsp;<br />&nbsp;&nbsp; Point2d&amp; mult( float );&nbsp; //2<br />&nbsp;&nbsp; float y() const { return _y; }&nbsp; //3</p><p>protected:&nbsp;<br />&nbsp;&nbsp; float _y;&nbsp;<br />};</p></blockquote><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>2、</strong>在Point2d的对象pt2d中，有三个东西，首先是继承自基类pt对象的数据成员_x，然后是pt2d对象本身的数据成员_y，最后是_vptr_Point。其中_vptr_Point指向着virtual table point2d。由于Point2d继承自Point，所以在virtual table point2d中存储着：改写了的其中的~Point2d()、Point2d&amp; mult( float )、float y() const，以及未被改写的Point::z()函数。</p><blockquote style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><p>class Point3d: public Point2d {&nbsp;<br />public:&nbsp;<br />&nbsp;&nbsp; Point3d( float x = 0.0,&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float y = 0.0, float z = 0.0 )&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : Point2d( x, y ), _z( z ) {}&nbsp;<br />&nbsp;&nbsp; ~Point3d();</p><p>&nbsp;&nbsp; // overridden base class virtual functions&nbsp;<br />&nbsp;&nbsp; Point3d&amp; mult( float );&nbsp;<br />&nbsp;&nbsp; float z() const { return _z; }</p><p>&nbsp;&nbsp; // ... other operations ...&nbsp;<br />protected:&nbsp;<br />&nbsp;&nbsp; float _z;&nbsp;<br />};</p></blockquote><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>3、</strong>在Point3d的对象pt3d中，则有四个东西，一个是_x，一个是_vptr_Point，一个是_y，一个是_z。其中_vptr_Point指向着virtual table point3d。由于point3d继承自point2d，所以在virtual table point3d中存储着：已经改写了的point3d的~Point3d()，point3d::mult()的函数地址，和z()函数的地址，以及未被改写的point2d的y()函数地址。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">ok，上述1、2、3所有情况的详情，请参考下图。<br /><img src="http://www.cppblog.com/images/cppblog_com/mysileng/QQ截图20130513184606.jpg" width="532" height="571" alt="" /><br /><p style="font-size: 14px;">本文，日后可能会酌情考虑增补有关内容。ok，更多，可参考深度探索c++对象模型一书第四章。<br />最近几章难度都比较小，是考虑到狂想曲有深有浅的原则，后续章节会逐步恢复到相应难度。</p><p style="font-size: 14px;">&nbsp;</p><p style="font-size: 14px;"><span style="color: #800000;"><span style="font-size: 16px;">第四节、虚函数的布局与汇编层面的考察</span></span></p><p style="font-size: 14px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ivan、老梦的两篇文章继续对虚函数进行了一番深入，我看他们已经写得很好了，我就不饶舌了。ok，请看：1、<a href="http://blog.csdn.net/zhanglei8893/archive/2011/04/19/6333751.aspx" target="_blank" style="color: #336699; text-decoration: initial;">VC虚函数布局引发的问题</a>，2、从汇编层面深度剖析C++虚函数、<a href="http://blog.csdn.net/linyt/archive/2011/04/20/6336762.aspx" target="_blank" style="color: #336699; text-decoration: initial;"><span style="color: #002d93;">http://blog.csdn.net/linyt/archive/2011/04/20/6336762.aspx</span></a>。</p><p style="font-size: 14px;">&nbsp;</p><p style="font-size: 14px;"><span style="color: #800000;"><span style="font-size: 16px;">第五节、虚函数表的详解</span></span></p><p style="font-size: 14px;">&nbsp; &nbsp; 本节全部内容来自淄博的共享，非常感谢。注@molixiaogemao：<span style="font-family: Arial, Helvetica, sans-serif; line-height: 20px;"><strong>只有发生继承的时候且父类子类都有virtual的时候才会出现虚函数指针，请不要忘了虚函数出现的目的是为了实现多态</strong>。</span><br />&nbsp;</p><blockquote style="font-size: 14px; background-color: #ffffff;"><p><span style="font-size: 13px;"><strong>&nbsp;一般继承（无虚函数覆盖）</strong><br />&nbsp;下面，再让我们来看看继承时的虚函数表是什么样的。假设有如下所示的一个继承关系：<br /><img src="http://www.cppblog.com/images/cppblog_com/mysileng/QQ截图20130513184726.jpg" width="195" height="208" alt="" /><br /></span><p style="font-size: 14px;"><span style="font-size: 13px;">请注意，在这个继承关系中，子类没有重载任何父类的函数。那么，在派生类的实例中，</span></p><p style="font-size: 14px;"><span style="font-size: 13px;">&nbsp;对于实例：Derive d; 的虚函数表如下：</span></p><span style="font-size: 13px;"><img src="http://www.cppblog.com/images/cppblog_com/mysileng/QQ截图20130513184808.jpg" width="561" height="137" alt="" /><br /></span><p style="font-size: 14px;"><span style="font-size: 13px;">我们从表中可以看到下面几点，<br />&nbsp;1）覆盖的f()函数被放到了虚表中原来父类虚函数的位置。<br />&nbsp;2）没有被覆盖的函数依旧。<br />&nbsp;<br />&nbsp;这样，我们就可以看到对于下面这样的程序，<br />&nbsp;Base *b = new Derive();</span></p><p style="font-size: 14px;"><span style="font-size: 13px;">b-&gt;f();</span></p><p style="font-size: 14px;"><strong><span style="font-size: 13px;">由b所指的内存中的虚函数表的f()的位置已经被Derive::f()函数地址所取代，<br />于是在实际调用发生时，是Derive::f()被调用了。这就实现了多态。</span></strong></p><p style="font-size: 14px;"><br /><strong><span style="font-size: 13px;">多重继承（无虚函数覆盖）</span></strong></p><p style="font-size: 14px;"><span style="font-size: 13px;">下面，再让我们来看看多重继承中的情况，假设有下面这样一个类的继承关系（注意：子类并没有覆盖父类的函数）：</span></p><span style="font-size: 13px;"><img src="http://www.cppblog.com/images/cppblog_com/mysileng/QQ截图20130513184842.jpg" width="530" height="456" alt="" /><br /></span><p style="font-size: 14px;"><span style="font-size: 13px;">我们可以看到：<br />1） 每个父类都有自己的虚表。<br />2） 子类的成员函数被放到了第一个父类的表中。（所谓的第一个父类是按照声明顺序来判断的）</span></p><p style="font-size: 14px;"><span style="font-size: 13px;">这样做就是为了解决不同的父类类型的指针指向同一个子类实例，而能够调用到实际的函数。</span></p><p style="font-size: 14px;"><br /><span style="font-size: 13px;"><strong>多重继承（有虚函数覆盖）</strong><br />下面我们再来看看，如果发生虚函数覆盖的情况。<br />下图中，我们在子类中覆盖了父类的f()函数。</span></p><span style="font-size: 13px;"><img src="http://www.cppblog.com/images/cppblog_com/mysileng/QQ截图20130513184926.jpg" width="455" height="442" alt="" /><br /></span><p style="font-size: 14px;"><span style="font-size: 13px;">我们可以看见，三个父类虚函数表中的f()的位置被替换成了子类的函数指针。<br />这样，我们就可以任一静态类型的父类来指向子类，并调用子类的f()了。如：</span></p><p style="font-size: 14px;"><span style="font-size: 13px;">Derive d;<br />Base1 *b1 = &amp;d;<br />Base2 *b2 = &amp;d;<br />Base3 *b3 = &amp;d;<br />b1-&gt;f(); //Derive::f()<br />b2-&gt;f(); //Derive::f()<br />b3-&gt;f(); //Derive::f()<br />b1-&gt;g(); //Base1::g()<br />b2-&gt;g(); //Base2::g()<br />b3-&gt;g(); //Base3::g()</span></p><p style="font-size: 14px;"><span style="font-size: 13px;">&nbsp;</span></p><p style="font-size: 14px;"><span style="font-size: 13px;"><strong>安全性</strong><br />每次写C++的文章，总免不了要批判一下C++。<br />这篇文章也不例外。通过上面的讲述，相信我们对虚函数表有一个比较细致的了解了。<br />水可载舟，亦可覆舟。下面，让我们来看看我们可以用虚函数表来干点什么坏事吧。</span></p><p style="font-size: 14px;"><span style="font-size: 13px;"><strong>一、通过父类型的指针访问子类自己的虚函数</strong><br />我们知道，子类没有重载父类的虚函数是一件毫无意义的事情。因为多态也是要基于函数重载的。<br />虽然在上面的图中我们可以看到Base1的虚表中有Derive的虚函数，但我们根本不可能使用下面的语句来调用子类的自有虚函数：</span></p><p style="font-size: 14px;"><span style="font-size: 13px;">Base1 *b1 = new Derive();<br />b1-&gt;g1(); //编译出错</span></p><p style="font-size: 14px;"><span style="font-size: 13px;">任何妄图使用父类指针想调用子类中的未覆盖父类的成员函数的行为都会被编译器视为非法，<span style="text-decoration: underline;">即基类指针不能调用子类自己定义的成员函数。</span>所以，这样的程序根本无法编译通过。<br />但在运行时，我们可以通过指针的方式访问虚函数表来达到违反C++语义的行为。<br />（关于这方面的尝试，通过阅读后面附录的代码，相信你可以做到这一点）</span></p><p style="font-size: 14px;"><span style="font-size: 13px;"><strong>二、访问non-public的虚函数</strong><br />另外，如果父类的虚函数是private或是protected的，但这些非public的虚函数同样会存在于虚函数表中，<br />所以，我们同样可以使用访问虚函数表的方式来访问这些non-public的虚函数，这是很容易做到的。<br />如：</span></p><p style="font-size: 14px;"><span style="font-size: 13px;">class Base {<br />private:&nbsp;<br />&nbsp;virtual void f() { cout &lt;&lt; "Base::f" &lt;&lt; endl; }&nbsp;<br />};</span></p><p style="font-size: 14px;"><span style="font-size: 13px;">class Derive : public Base{&nbsp;<br />};<br />typedef void(*Fun)(void);<br />void main() {<br />&nbsp;Derive d;<br /><strong>&nbsp;Fun pFun = (Fun)*((int*)*(int*)(&amp;d)+0);</strong><br />&nbsp;pFun();&nbsp;<br />}</span></p><p style="font-size: 14px;"><span style="font-size: 13px;">对上面粗体部分的解释（@a &amp;&amp; x</span><span style="font-size: 13px;">）：</span></p><p style="font-size: 14px;"><span style="font-size: 13px;">1. (int*)(&amp;d)取vptr地址，该地址存储的是指向vtbl的指针<br />2. (int*)*(int*)(&amp;d)取vtbl地址，该地址存储的是虚函数表数组<br />3. (Fun)*((int*)*(int*)(&amp;d) +0)，取vtbl数组的第一个元素，即Base中第一个虚函数f的地址<br />4. (Fun)*((int*)*(int*)(&amp;d) +1)，取vtbl数组的第二个元素（这第4点，如下图所示）。</span></p><p style="font-size: 14px;"><span style="font-size: 13px;">下图也能很清晰的说明一些东西（@5）：</span></p><span style="font-size: 13px;"><img src="http://www.cppblog.com/images/cppblog_com/mysileng/QQ截图20130513185001.jpg" width="631" height="461" alt="" /><br /></span><blockquote style="font-size: 14px; background-color: #ffffff;"><p><span style="font-size: 13px;">ok，再来看一个问题，如果一个子类重载的虚拟函数为privete，那么通过父类的指针可以访问到它吗？</span></p><p><span style="font-size: 13px;">#include &lt;IOSTREAM&gt;&nbsp;&nbsp;&nbsp;<br />class B&nbsp;&nbsp;&nbsp;<br />{&nbsp;&nbsp; &nbsp;<br />public:&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; virtual void fun()&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp; &nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::cout &lt;&lt; "base fun called";&nbsp;&nbsp; &nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp; };&nbsp;&nbsp; &nbsp;<br />};&nbsp;&nbsp;</span></p><p><span style="font-size: 13px;">class D : public B&nbsp;&nbsp;&nbsp;&nbsp;<br />{&nbsp;&nbsp; &nbsp;<br />private:&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp; virtual void fun()&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp; &nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::cout &lt;&lt; "driver fun called";&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; };&nbsp;&nbsp; &nbsp;<br />};&nbsp;&nbsp;</span></p><p><span style="font-size: 13px;">int main(int argc, char* argv[])&nbsp;&nbsp;&nbsp;<br />{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; B* p = new D();&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; p-&gt;fun();&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; return 0;&nbsp;&nbsp; &nbsp;<br />}&nbsp;&nbsp;</span><span style="font-size: 13px;"><br /><strong>运行时会输出 driver fun called</strong></span></p><p><span style="font-size: 13px;">从这个实验，可以更深入的了解虚拟函数编译时的一些特征:<br />在编译虚拟函数调用的时候，例如p-&gt;fun(); 只是按其静态类型来处理的, 在这里p的类型就是B，不会考虑其实际指向的类型（动态类型）。</span><br /><span style="font-size: 13px;">&nbsp;&nbsp;&nbsp; 也就是说，碰到p-&gt;fun();编译器就当作调用B的fun来进行相应的检查和处理。<br />因为在B里fun是public的，所以这里在&#8220;访问控制检查&#8221;这一关就完全可以通过了。<br />然后就会转换成(*p-&gt;vptr[1])(p)这样的方式处理, p实际指向的动态类型是D，<br />&nbsp;&nbsp;&nbsp; 所以p作为参数传给fun后(类的非静态成员函数都会编译加一个指针参数，指向调用该函数的对象，我们平常用的this就是该指针的值）, 实际运行时p-&gt;vptr[1]则获取到的是D::fun()的地址，也就调用了该函数, 这也就是动态运行的机理。</span></p><p><br /><span style="font-size: 13px;">为了进一步的实验，可以将B里的fun改为private的，D里的改为public的，则编译就会出错。<br />C++的注意条款中有一条" 绝不重新定义继承而来的缺省参数值"&nbsp;<br />（Effective C++ Item37， never redefine a function's inherited default parameter value) 也是同样的道理。</span></p><p><span style="font-size: 13px;"><strong>可以再做个实验</strong><br />class B&nbsp;&nbsp;&nbsp;<br />{&nbsp;&nbsp; &nbsp;<br />public:&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp; virtual void fun(int i = 1)&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp; &nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::cout &lt;&lt; "base fun called, " &lt;&lt; i;&nbsp;&nbsp; &nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp; };&nbsp;&nbsp; &nbsp;<br />};&nbsp;&nbsp;</span></p><p><span style="font-size: 13px;">class D : public B&nbsp;&nbsp;&nbsp;&nbsp;<br />{&nbsp;&nbsp; &nbsp;<br />private:&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; virtual void fun(int i = 2)&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp; &nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::cout &lt;&lt; "driver fun called, " &lt;&lt; i;&nbsp;&nbsp; &nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp; };&nbsp;&nbsp; &nbsp;<br />};&nbsp;</span></p><p>&nbsp;</p><p>&nbsp;</p><strong><span style="font-size: 13px;">则运行会输出driver fun called, 1</span></strong><p>&nbsp;</p><p><span style="font-size: 13px;">关于这一点，Effective上讲的很清楚&#8220;virtual 函数系动态绑定， 而缺省参数却是静态绑定&#8221;，<br />也就是说在编译的时候已经按照p的静态类型处理其默认参数了,转换成了(*p-&gt;vptr[1])(p, 1)这样的方式。</span><span style="font-size: 13px;">&nbsp;</span></p><p><strong><span style="font-size: 13px;">补遗</span></strong></p><p><span style="font-size: 13px;">&nbsp;&nbsp; 一个类如果有虚函数，不管是几个虚函数，都会为这个类声明一个虚函数表，这个虚表是一个含有虚函数的类的，不是说是类对象的。一个含有虚函数的类，不管有多少个数据成员，每个对象实例都有一个虚指针，在内存中，存放每个类对象的内存区，在内存区的头部都是先存放这个指针变量的（准确的说，应该是：视编译器具体情况而定），从第n（n视实际情况而定）个字节才是这个对象自己的东西。</span></p><p>&nbsp;</p><p><span style="font-size: 13px;">下面再说下通过基类指针，调用虚函数所发生的一切：<br />One *p;<br />p-&gt;disp();</span></p><p><span style="font-size: 13px;">1、上来要取得类的虚表的指针，就是要得到，虚表的地址。存放类对象的内存区的前四个字节其实就是用来存放虚表的地址的。<br />2、得到虚表的地址后，从虚表那知道你调用的那个函数的入口地址。根据虚表提供的你要找的函数的地址。并调用函数；你要知道，那个虚表是一个存放指针变量的数组，并不是说，那个虚表中就是存放的虚函数的实体。</span></p></blockquote><p style="font-size: 14px;">本章完。</p></p></blockquote><br /><br /></p><img src ="http://www.cppblog.com/mysileng/aggbug/200230.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2013-05-13 18:51 <a href="http://www.cppblog.com/mysileng/archive/2013/05/13/200230.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序员编程艺术-----第七章-----求连续子数组的最大和</title><link>http://www.cppblog.com/mysileng/archive/2013/05/13/200229.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Mon, 13 May 2013 10:44:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2013/05/13/200229.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/200229.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2013/05/13/200229.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/200229.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/200229.html</trackback:ping><description><![CDATA[<p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff; padding-left: 120px;"><span style="font-size: medium;">&nbsp;程序员编程艺术：第七章、求连续子数组的最大和&nbsp;</span></p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">作者：July。<br />出处：<a href="http://blog.csdn.net/v_JULY_v" target="_blank" style="color: #336699; text-decoration: initial;"><strong><span style="color: #002d93;">http://blog.csdn.net/v_JULY_v</span>&nbsp;</strong></a>。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><br /><span style="font-size: medium;"><span style="color: #800000;">前奏</span></span></p><ul style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><li>希望更多的人能和我一样，把本狂想曲系列中的任何一道面试题当做一道简单的编程题或一个实质性的问题来看待，在阅读本狂想曲系列的过程中，希望你能尽量暂时放下所有有关面试的一切包袱，潜心攻克每一道&#8220;编程题&#8221;，在解决编程题的过程中，好好享受编程带来的无限乐趣，与思考带来的无限激情。--By<a href="http://weibo.com/julyweibo" target="_blank" style="color: #336699; text-decoration: initial;"><strong>@July_____</strong></a>。</li><li>原狂想曲系列已更名为：<a href="http://blog.csdn.net/v_JULY_v/category/784066.aspx" target="_blank" style="color: #336699; text-decoration: initial;"><strong>程序员编程艺术系列</strong></a>。原狂想曲创作组更名为<span style="text-decoration: underline;">编程艺术室</span>。编程艺术室致力于以下三点工作：1、针对一个问题，不断寻找更高效的算法，并予以编程实现。2、解决实际中会碰到的应用问题，如<a href="http://blog.csdn.net/v_JULY_v/archive/2011/05/28/6451990.aspx" target="_blank" style="color: #336699; text-decoration: initial;"><span style="color: #800000;"><strong>第十章、如何给10^7个数据量的磁盘文件排序</strong></span></a>。3、经典算法的研究与实现。总体突出一点：编程，如何高效的编程解决实际问题。欢迎有志者加入。</li></ul><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><br /><span style="color: #800000;"><span style="font-size: medium;">第一节、求子数组的最大和</span></span><br /><strong>3.求子数组的最大和</strong><br /><strong>题目描述：</strong><br />输入一个整形数组，数组里有正数也有负数。<br />数组中连续的一个或多个整数组成一个子数组，每个子数组都有一个和。<br />求所有子数组的和的最大值。要求时间复杂度为O(n)。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5，和最大的子数组为3, 10, -4, 7, 2，<br />因此输出为该子数组的和18。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><strong>分析：</strong>这个问题在各大公司面试中出现频率之频繁，被人引用次数之多，非一般面试题可与之匹敌。单凭这点，就没有理由不入选狂想曲系列中了。此题曾作为本人之前整理的微软100题中的第3题，至今反响也很大。ok，下面，咱们来一步一步分析这个题：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>1、</strong>求一个数组的最大子数组和，如此序列1, -2, 3, 10, -4, 7, 2, -5，我想最最直观也是最野蛮的办法便是，三个for循环三层遍历，求出数组中每一个子数组的和，最终求出这些子数组的最大的一个值。<br />记Sum[i, &#8230;, j]为数组A中第i个元素到第j个元素的和（其中0 &lt;= i &lt;= j &lt; n），遍历所有可能的Sum[i, &#8230;, j]，那么时间复杂度为O（N^3）：</p><blockquote style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><p>//本段代码引自编程之美<br />int MaxSum(int* A, int n)<br />{<br />&nbsp;int maximum = -INF;&nbsp;<br />&nbsp;int sum=0;&nbsp;&nbsp;&nbsp;<br />&nbsp;for(int i = 0; i &lt; n; i++)<br />&nbsp;{<br />&nbsp;&nbsp;for(int j = i; j &lt; n; j++)<br />&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;for(int k = i; k &lt;= j; k++)<br />&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;sum += A[k];<br />&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;if(sum &gt; maximum)<br />&nbsp;&nbsp;&nbsp;&nbsp;maximum = sum;</p><p>&nbsp;&nbsp; sum=0;&nbsp;&nbsp;&nbsp;//这里要记得清零，否则的话sum最终存放的是所有子数组的和。也就是编程之美上所说的bug。多谢苍狼。<br />&nbsp;&nbsp;}<br />&nbsp;}<br />&nbsp;return maximum;<br />}&nbsp;</p></blockquote><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>2、</strong>其实这个问题，在我之前上传的微软100题，答案V0.2版[第1-20题答案]，便直接给出了以下O（N）的算法：</p><div bg_cpp"="" style="border: 1px dashed #999999; background-color: #f5f5f5; width: 687.0499877929688px;"><ol start="1" style="margin-bottom: 0px; margin-left: 0px; padding-top: 5px; padding-bottom: 5px; position: relative;"><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//copyright@&nbsp;July&nbsp;2010/10/18</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//updated，2011.05.25.</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">#include&nbsp;&lt;iostream.h&gt;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;maxSum(<span style="color: #2e8b57; font-weight: bold;">int</span>*&nbsp;a,&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;n)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;sum=0;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//其实要处理全是负数的情况，很简单，如稍后下面第3点所见，直接把这句改成："int&nbsp;sum=a[0]"即可</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//也可以不改，当全是负数的情况，直接返回0，也不见得不行。</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;b=0;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>(<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;i=0;&nbsp;i&lt;n;&nbsp;i++)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(b&lt;0)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//...</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b=a[i];&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">else</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b+=a[i];&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(sum&lt;b)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sum=b;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;sum;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;main()&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;a[10]={1,&nbsp;-2,&nbsp;3,&nbsp;10,&nbsp;-4,&nbsp;7,&nbsp;2,&nbsp;-5};&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//int&nbsp;a[]={-1,-2,-3,-4};&nbsp;&nbsp;//测试全是负数的用例</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;maxSum(a,8)&lt;&lt;endl;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;0;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">/*-------------------------------------</span>&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">解释下：</span>&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">例如输入的数组为1,&nbsp;-2,&nbsp;3,&nbsp;10,&nbsp;-4,&nbsp;7,&nbsp;2,&nbsp;-5，</span>&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">那么最大的子数组为3,&nbsp;10,&nbsp;-4,&nbsp;7,&nbsp;2，</span>&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">因此输出为该子数组的和18。</span>&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">所有的东西都在以下俩行，</span>&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">即：</span>&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">b&nbsp;&nbsp;：&nbsp;&nbsp;0&nbsp;&nbsp;1&nbsp;&nbsp;-1&nbsp;&nbsp;3&nbsp;&nbsp;13&nbsp;&nbsp;&nbsp;9&nbsp;&nbsp;16&nbsp;&nbsp;18&nbsp;&nbsp;13&nbsp;&nbsp;</span>&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">sum：&nbsp;&nbsp;0&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;3&nbsp;&nbsp;13&nbsp;&nbsp;13&nbsp;&nbsp;16&nbsp;&nbsp;18&nbsp;&nbsp;18</span>&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">&nbsp;&nbsp;</span>&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">其实算法很简单，当前面的几个数，加起来后，b&lt;0后，</span>&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">把b重新赋值，置为下一个元素，b=a[i]。</span>&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">当b&gt;sum，则更新sum=b;</span>&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">若b&lt;sum，则sum保持原值，不更新。。July、10/31。</span>&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">----------------------------------*/</span>&nbsp;&nbsp;</li></ol></div><p>&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>3、</strong>不少朋友看到上面的答案之后，认为上述思路2的代码，没有处理全是负数的情况，当全是负数的情况时，我们可以让程序返回0，也可以让其返回最大的那个负数，下面便是前几日重写的，修改后的处理全是负数情况（返回最大的负数）的代码：</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"></p><div bg_cpp"="" style="border: 1px dashed #999999; background-color: #f5f5f5; width: 687.0499877929688px;"><ol start="1" style="margin-bottom: 0px; margin-left: 0px; padding-top: 5px; padding-bottom: 5px; position: relative;"><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//copyright@&nbsp;July</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//July、updated，2011.05.25。</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">#include&nbsp;&lt;iostream.h&gt;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">#define&nbsp;n&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//多定义了一个变量&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;maxsum(<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;a[n])&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//于此处，你能看到上述思路2代码（指针）的优势</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;max=a[0];&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//全负情况，返回最大数</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;sum=0;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>(<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;j=0;j&lt;n;j++)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(sum&gt;=0)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//如果加上某个元素，sum&gt;=0的话，就加</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sum+=a[j];&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">else</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sum=a[j];&nbsp;&nbsp;<span style="color: #999999;">//如果加上某个元素，sum&lt;0了，就不加</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(sum&gt;max)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;max=sum;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;max;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;main()&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;a[]={-1,-2,-3,-4};&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;maxsum(a)&lt;&lt;endl;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;0;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">}&nbsp;&nbsp;</li></ol></div><p>&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>4、</strong>DP解法的具体方程：@<span style="text-decoration: underline;"><span style="background-color: #ffffdd; color: #0000ff;"><strong>&nbsp;</strong></span></span><strong><span style="background-color: #ffffdd;">flyinghearts</span></strong>：设sum[i] 为前i个元素中，包含第i个元素且和最大的连续子数组，result 为已找到的子数组中和最大的。对第i+1个元素有两种选择：做为新子数组的第一个元素、放入前面找到的子数组。<br />sum[i+1] = max(a[i+1], sum[i] + a[i+1])<br />result = max(result, sum[i])<br />&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><strong>扩展：</strong><br />1、如果数组是二维数组，同样要你求最大子数组的和列?<br />2、如果是要你求子数组的最大乘积列?<br />3、如果同时要求输出子段的开始和结束列?</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><span style="font-size: medium;"><span style="color: #800000;">第二节、Data structures and Algorithm analysis in C</span></span></p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">下面给出《Data structures and Algorithm analysis in C》中4种实现。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"></p><div bg_cpp"="" style="border: 1px dashed #999999; background-color: #f5f5f5; width: 687.0499877929688px;"><ol start="1" style="margin-bottom: 0px; margin-left: 0px; padding-top: 5px; padding-bottom: 5px; position: relative;"><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//感谢网友firo</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//July、2010.06.05。</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//Algorithm&nbsp;1:时间效率为O(n*n*n)</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;MaxSubsequenceSum1(<span style="color: #0000ff;">const</span>&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;A[],<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;N)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;ThisSum=0&nbsp;,MaxSum=0,i,j,k;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>(i=0;i&lt;N;i++)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>(j=i;j&lt;N;j++)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThisSum=0;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>(k=i;k&lt;j;k++)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThisSum+=A[k];&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(ThisSum&gt;MaxSum)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MaxSum=ThisSum;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;MaxSum;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//Algorithm&nbsp;2:时间效率为O(n*n)</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;MaxSubsequenceSum2(<span style="color: #0000ff;">const</span>&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;A[],<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;N)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;ThisSum=0,MaxSum=0,i,j,k;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>(i=0;i&lt;N;i++)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThisSum=0;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>(j=i;j&lt;N;j++)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThisSum+=A[j];&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(ThisSum&gt;MaxSum)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MaxSum=ThisSum;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;MaxSum;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//Algorithm&nbsp;3:时间效率为O(n*log&nbsp;n)</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//算法3的主要思想：采用二分策略，将序列分成左右两份。</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//那么最长子序列有三种可能出现的情况，即</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//【1】只出现在左部分.</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//【2】只出现在右部分。</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//【3】出现在中间，同时涉及到左右两部分。</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//分情况讨论之。</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #0000ff;">static</span>&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;MaxSubSum(<span style="color: #0000ff;">const</span>&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;A[],<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;Left,<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;Right)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;MaxLeftSum,MaxRightSum;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//左、右部分最大连续子序列值。对应情况【1】、【2】</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;MaxLeftBorderSum,MaxRightBorderSum;&nbsp;&nbsp;<span style="color: #999999;">//从中间分别到左右两侧的最大连续子序列值，对应case【3】。</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;LeftBorderSum,RightBorderSum;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;Center,i;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(Left&nbsp;==&nbsp;Right)Base&nbsp;Case&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(A[Left]&gt;0)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;A[Left];&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">else</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;0;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Center=(Left+Right)/2;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MaxLeftSum=MaxSubSum(A,Left,Center);&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MaxRightSum=MaxSubSum(A,Center+1,Right);&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MaxLeftBorderSum=0;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LeftBorderSum=0;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>(i=Center;i&gt;=Left;i--)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LeftBorderSum+=A[i];&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(LeftBorderSum&gt;MaxLeftBorderSum)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MaxLeftBorderSum=LeftBorderSum;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MaxRightBorderSum=0;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RightBorderSum=0;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>(i=Center+1;i&lt;=Right;i++)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RightBorderSum+=A[i];&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(RightBorderSum&gt;MaxRightBorderSum)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MaxRightBorderSum=RightBorderSum;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;max1=MaxLeftSum&gt;MaxRightSum?MaxLeftSum:MaxRightSum;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;max2=MaxLeftBorderSum+MaxRightBorderSum;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;max1&gt;max2?max1:max2;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//Algorithm&nbsp;4:时间效率为O(n)</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #999999;">//同上述第一节中的思路3、和4。</span>&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;"><span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;MaxSubsequenceSum(<span style="color: #0000ff;">const</span>&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;A[],<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;N)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;ThisSum,MaxSum,j;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;ThisSum=MaxSum=0;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>(j=0;j&lt;N;j++)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThisSum+=A[j];&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(ThisSum&gt;MaxSum)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MaxSum=ThisSum;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">else</span>&nbsp;<span style="color: #0000ff;">if</span>(ThisSum&lt;0)&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThisSum=0;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;MaxSum;&nbsp;&nbsp;</li><li style="border-left-style: none; line-height: 13px;">}&nbsp;&nbsp;&nbsp;</li></ol></div>&nbsp;&nbsp;<p>&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">本章完。</p><img src ="http://www.cppblog.com/mysileng/aggbug/200229.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2013-05-13 18:44 <a href="http://www.cppblog.com/mysileng/archive/2013/05/13/200229.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序员编程艺术-----第六章-----求解500万以内的亲和数(素数、完数)</title><link>http://www.cppblog.com/mysileng/archive/2013/05/13/200226.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Mon, 13 May 2013 09:43:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2013/05/13/200226.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/200226.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2013/05/13/200226.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/200226.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/200226.html</trackback:ping><description><![CDATA[<p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">作者：上善若水、July、yansha。<br />出处：<a href="http://blog.csdn.net/v_JULY_v" target="_blank" style="color: #336699; text-decoration: initial;"><strong><span style="color: #002d93;">http://blog.csdn.net/v_JULY_v</span>&nbsp;</strong></a>。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><br /><span style="color: #800000;"><span style="font-size: medium;">前奏</span></span><br />&nbsp;&nbsp;&nbsp; 本章陆续开始，除了继续保持原有的字符串、数组等面试题之外，会有意识的间断性节选一些有关数字趣味小而巧的面试题目，重在突出思路的&#8220;巧&#8221;，和&#8220;妙&#8221;。本章亲和数问题之关键字，&#8220;500万&#8221;，&#8220;线性复杂度&#8221;。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><span style="font-size: medium;"><span style="color: #800000;">第一节、亲和数问题</span></span><br />题目描述：<br />求500万以内的所有亲和数<br />如果两个数a和b，a的所有真因数之和等于b,b的所有真因数之和等于a,则称a,b是一对亲和数。<br />例如220和284，1184和1210，2620和2924。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><strong>分析：<br /></strong>&nbsp;&nbsp;&nbsp; 首先得明确到底是什么是亲和数?</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">亲和数问题最早是由毕达哥拉斯学派发现和研究的。他们在研究数字的规律的时候发现有以下性质特点的两个数：<br />220的真因子是：1、2、4、5、10、11、20、22、44、55、110；<br />284的真因子是：1、2、4、71、142。<br />而这两个数恰恰等于对方的真因子各自加起来的和（sum[i]表示数i 的各个真因子的和），即<br />220=1+2+4+71+142=sum[284],<br />284=1+2+4+5+10+11+20+22+44+55+110=sum[220]。<br />得284的真因子之和sum[284]=220，且220的真因子之和sum[220]=284，即有sum[220]=sum[sum[284]]=284。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">如此，是否已看出丝毫端倪?</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">如上所示，考虑到1是每个整数的因子，把出去整数本身之外的所有因子叫做这个数的&#8220;真因子&#8221;。如果两个整数，其中每一个真因子的和都恰好等于另一个数，那么这两个数，就构成一对&#8220;亲和数&#8221;（有关亲和数的更多讨论，可参考这：<a title="http://en.wikipedia.org/wiki/Amicable_pair" href="http://t.cn/hesH09?u=1580904460" target="_blank" style="color: #336699; text-decoration: initial;"><span style="color: #0082cb;">http://t.cn/hesH09</span></a>）。</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;</p><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><strong>求解：</strong><br />&nbsp;&nbsp;&nbsp; 了解了什么是亲和数，接下来咱们一步一步来解决上面提出的问题（以下内容大部引自水的原话，同时水哥有一句原话，&#8220;<strong>在你真正弄弄懂这个范例之前，你不配说你懂数据结构和算法</strong>&#8221;）。</p><ol style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><li>看到这个问题后，第一想法是什么？模拟搜索+剪枝？回溯？时间复杂度有多大？其中bn为an的伪亲和数，即bn是an的真因数之和大约是多少？至少是10^13（@iicup：N^1.5 对于5*10^6 , 次数大致 10^10 而不是 10^13.）的数量级的。那么对于每秒千万次运算的计算机来说，大概在1000多天也就是3年内就可以搞定了（iicup的计算: 10^13 / 10^7 =1000000(秒) 大约 278 小时. ）。如果是基于这个基数在优化，你无法在一天内得到结果的。</li><li>一个不错的算法应该在半小时之内搞定这个问题，当然这样的算法有很多。节约时间的做法是可以生成伴随数组，也就是空间换时间，但是那样，空间代价太大，因为数据规模庞大。</li><li>在稍后的算法中，依然使用的伴随数组，只不过，因为题目的特殊性，只是它方便和巧妙地利用了下标作为伴随数组，来节约时间。同时，将回溯的思想换成递推的思想（预处理数组的时间复杂度为logN（调和级数）*N，扫描数组的时间复杂度为线性O（N）。所以，总的时间复杂度为O（N*logN+N）（其中logN为调和级数）&nbsp;&nbsp;）。</li></ol><p style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><br /><span style="color: #800000;"><span style="font-size: medium;">第二节、伴随数组线性遍历</span></span><br />依据上文中的第3点思路，编写如下代码：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;sum[</span><span style="color: #000000; ">5000010</span><span style="color: #000000; ">];&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">为防越界&nbsp;&nbsp;</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;<br /></span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;main()&nbsp;&nbsp;&nbsp;<br />{&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;i,&nbsp;j;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;(i&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;&nbsp;i&nbsp;</span><span style="color: #000000; ">&lt;=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">5000000</span><span style="color: #000000; ">;&nbsp;i</span><span style="color: #000000; ">++</span><span style="color: #000000; ">)&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sum[i]&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">1是所有数的真因数所以全部置1&nbsp;&nbsp;</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;(i&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">2</span><span style="color: #000000; ">;&nbsp;i&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;i&nbsp;</span><span style="color: #000000; ">&lt;=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">5000000</span><span style="color: #000000; ">;&nbsp;i</span><span style="color: #000000; ">++</span><span style="color: #000000; ">)&nbsp;&nbsp;</span><span style="color: #008000; ">&nbsp;&nbsp;</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">5000000以下最大的真因数是不超过它的一半的&nbsp;&nbsp;</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;i&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;i;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">因为真因数，所以不能算本身，所以从它的2倍开始&nbsp;&nbsp;</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">while</span><span style="color: #000000; ">&nbsp;(j&nbsp;</span><span style="color: #000000; ">&lt;=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">5000000</span><span style="color: #000000; ">)&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">将所有i的倍数的位置上加i&nbsp;&nbsp;</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sum[j]&nbsp;</span><span style="color: #000000; ">+=</span><span style="color: #000000; ">&nbsp;i;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j&nbsp;</span><span style="color: #000000; ">+=</span><span style="color: #000000; ">&nbsp;i;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;(i&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">220</span><span style="color: #000000; ">;&nbsp;i&nbsp;</span><span style="color: #000000; ">&lt;=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">5000000</span><span style="color: #000000; ">;&nbsp;i</span><span style="color: #000000; ">++</span><span style="color: #000000; ">)&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">扫描，O（N）。&nbsp;&nbsp;</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;一次遍历，因为知道最小是220和284因此从220开始&nbsp;&nbsp;</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(sum[i]&nbsp;</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;i&nbsp;</span><span style="color: #000000; ">&amp;&amp;</span><span style="color: #000000; ">&nbsp;sum[i]&nbsp;</span><span style="color: #000000; ">&lt;=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">5000000</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">&amp;&amp;</span><span style="color: #000000; ">&nbsp;sum[sum[i]]&nbsp;</span><span style="color: #000000; ">==</span><span style="color: #000000; ">&nbsp;i)&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">去重，不越界，满足亲和&nbsp;&nbsp;</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">%d&nbsp;%d/n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,i,sum[i]);&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;&nbsp;&nbsp;<br />} &nbsp;</span></div><p style="font-size: 14px;"><span style="font-size: medium;"><span style="color: #800000;">第三节、程序的构造与解释</span></span><br />&nbsp;&nbsp;&nbsp; 我再来具体解释下上述程序的原理，ok，举个例子，假设是求10以内的亲和数，求解步骤如下：</p><p style="font-size: 14px;">因为所有数的真因数都包含1，所以，先在各个数的下方全部置1</p><ol style="font-size: 14px;"><li>然后取i=2,3,4,5（i&lt;=10/2），j依次对应的位置为j=（4、6、8、10），（6、9）,（8）,（10）各数所对应的位置。</li><li>依据j所找到的位置，在j所指的各个数的下面加上各个真因子i（i=2、3、4、5）。<br />整个过程，即如下图所示（如sum[6]=1+2+3=6，sum[10]=1+2+5=8.）：<br />1&nbsp; 2&nbsp; 3&nbsp; 4 &nbsp;5&nbsp; 6&nbsp; 7&nbsp; 8&nbsp; 9&nbsp; 10<br />1&nbsp; 1&nbsp; 1&nbsp; 1&nbsp; 1&nbsp; 1&nbsp; 1&nbsp; 1&nbsp; 1&nbsp; 1<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;2<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5</li><li>然后一次遍历i从220开始到5000000，i每遍历一个数后，<br />将i对应的数下面的各个真因子加起来得到一个和sum[i]，如果这个和sum[i]==某个i&#8217;，且sum[i&#8216;]=i，<br />那么这两个数i和i&#8217;，即为一对亲和数。</li><li>i=2；sum[4]+=2，sum[6]+=2，sum[8]+=2，sum[10]+=2，sum[12]+=2...<br />i=3，sum[6]+=3，sum[9]+=3...<br />......</li><li>i=220时，sum[220]=284，i=284时，sum[284]=220；即sum[220]=sum[sum[284]]=284，<br />得出220与284是一对亲和数。所以，最终输出220、284，...</li></ol><br /><br /><br /></p><img src ="http://www.cppblog.com/mysileng/aggbug/200226.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2013-05-13 17:43 <a href="http://www.cppblog.com/mysileng/archive/2013/05/13/200226.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序员编程艺术-----第五章-----寻找满足和为定值的两个或多个数</title><link>http://www.cppblog.com/mysileng/archive/2012/11/30/195849.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Fri, 30 Nov 2012 13:09:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/11/30/195849.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/195849.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/11/30/195849.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/195849.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/195849.html</trackback:ping><description><![CDATA[<p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 程序员编程艺术：第五章、寻找和为定值的两个或多个数<br />&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 作者：July，yansha，zhouzhenren。<br />&nbsp;&nbsp;&nbsp; 致谢：微软100题实现组，编程艺术室。<br />&nbsp;&nbsp;&nbsp; 微博：<a href="http://weibo.com/julyweibo" target="_blank" style="color: #336699; text-decoration: initial;"><strong><span style="color: #002d93;">http://weibo.com/julyweibo</span>&nbsp;</strong></a>&nbsp; 。<br />&nbsp;&nbsp;&nbsp; 出处：<a href="http://blog.csdn.net/v_JULY_v" target="_blank" style="color: #336699; text-decoration: initial;"><strong><span style="color: #002d93;">http://blog.csdn.net/v_JULY_v</span>&nbsp;</strong></a>&nbsp;。<br />&nbsp;&nbsp;&nbsp; wiki：<a href="http://tctop.wikispaces.com/" target="_blank" style="color: #336699; text-decoration: initial;"><span style="color: #002d93;"><strong>http://tctop.wikispaces.com/</strong></span></a>。<br />------------------------------</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="color: #800000;">前奏</span></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp; 希望此编程艺术系列能给各位带来的是一种方法，一种创造力，一种举一反三的能力。本章依然同第四章一样，选取比较简单的面试题，恭祝各位旅途愉快。同样，有任何问题，欢迎不吝指正。谢谢。</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><br /><span style="color: #800000;">第一节、寻找和为定值的两个数</span><br />第14题（数组）：<br />题目：输入一个数组和一个数字，在数组中查找两个数，使得它们的和正好是输入的那个数字。<br />要求时间复杂度是O(n)。如果有多对数字的和等于输入的数字，输出任意一对即可。<br />例如输入数组1、2、4、7、11、15和数字15。由于4+11=15，因此输出4和11。</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><strong>分析</strong>：</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">咱们试着一步一步解决这个问题（<span style="color: #3366ff;">注意阐述中数列有序无序的区别</span>）：</p><ol style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><li>直接穷举，从数组中任意选取两个数，判定它们的和是否为输入的那个数字。此举复杂度为O（N^2）。很显然，我们要寻找效率更高的解法。</li><li>题目相当于，对每个a[i]，然后查找判断sum-a[i]是否也在原始序列中，每一次要查找的时间都要花费为O（N），这样下来，最终找到两个数还是需要O（N^2）的复杂度。那如何提高查找判断的速度列?对了，二分查找，将原来O（N）的查找时间提高到O（logN），这样对于N个a[i]，都要花logN的时间去查找相对应的sum-a[i]是否在原始序列中，总的时间复杂度已降为O（N*logN），且空间复杂度为O（1）。（<strong>如果有序，直接二分O（N*logN），如果无序，先排序后二分，复杂度同样为O（N*logN+N*logN）=O（N*logN</strong>），<strong>空间总为O（1））。</strong></li><li>有没有更好的办法列?咱们可以依据上述思路2的思想，a[i]在序列中，如果a[i]+a[k]=sum的话，那么sum-a[i]（a[k]）也必然在序列中，，举个例子，如下：<br />原始序列：1、 2、 4、 7、11、15&nbsp;&nbsp;&nbsp;&nbsp; 用输入数字15减一下各个数，得到对应的序列为：<br />对应序列：14、13、11、8、4、 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />第一个数组以一指针i 从数组最左端开始向右扫描，第二个数组以一指针j 从数组最右端开始向左扫描，如果下面出现了和上面一样的数，即a[*i]=a[*j]，就找出这俩个数来了。如上，i，j最终在第一个，和第二个序列中找到了相同的数4和11，，所以符合条件的两个数，即为4+11=15。怎么样，两端同时查找，时间复杂度瞬间缩短到了O（N），但却同时需要O（N）的空间存储第二个数组（@飞羽：<span style="font-size: 12px;">要达到O(N)的复杂度，第一个数组以一指针i 从数组最左端开始向右扫描，第二个数组以一指针j 从数组最右端开始向左扫描，首先初始i指向元素1，j指向元素0，谁指的元素小，谁先移动，由于1（i）&gt;0（j），所以i不动，j向左移动。然后j移动到元素4发现大于元素1，故而停止移动j，开始移动i，直到i指向4，这时,i指向的元素与j指向的元素相等，故而判断4是满足条件的第一个数；然后同时移动i,j再进行判断，直到它们到达边界</span>）。</li><li>当然，你还可以构造hash表，正如编程之美上的所述，给定一个数字，根据hash映射查找另一个数字是否也在数组中，只需用O（1）的时间，这样的话，总体的算法通上述思路3 一样，也能降到O（N），但有个缺陷，就是构造hash额外增加了O（N）的空间，此点同上述思路 3。不过，空间换时间，仍不失为在时间要求较严格的情况下的一种好办法。</li><li>如果数组是无序的，先排序（n*logn），然后用两个指针i，j，各自指向数组的首尾两端，令i=0，j=n-1，然后i++，j--，逐次判断a[i]+a[j]?=sum，如果某一刻a[i]+a[j]&gt;sum，则要想办法让sum的值减小，所以此刻i不动，j--，如果某一刻a[i]+a[j]&lt;sum，则要想办法让sum的值增大，所以此刻i++，j不动。所以，数组无序的时候，时间复杂度最终为O（n*logn+n）=O（n*logn），若原数组是有序的，则不需要事先的排序，直接O（n）搞定，且空间复杂度还是O（1），此思路是相对于上述所有思路的一种改进<strong>。（如果有序，直接两个指针两端扫描，时间O（N），如果无序，先排序后两端扫描，时间O（N*logN+N）=O（N*logN），空间始终都为O（1））。（</strong>与上述思路2相比，排序后的时间开销由之前的二分的n*logn降到了扫描的O（N）<strong>）。</strong></li></ol><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><strong>总结</strong>：</p><ul style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><li>不论原序列是有序还是无序，解决这类题有以下三种办法：1、二分（若无序，先排序后二分），时间复杂度总为O（n*logn），空间复杂度为O（1）；2、扫描一遍X-S[i]&nbsp; 映射到一个数组或构造hash表，时间复杂度为O（n），空间复杂度为O（n）；3、两个指针两端扫描（若无序，先排序后扫描），时间复杂度最后为：有序O（n），无序O（n*logn+n）=O（n*logn），空间复杂度都为O（1）。</li><li>所以，要想达到时间O（N），空间O（1）的目标，除非原数组是有序的（指针扫描法），不然，当数组无序的话，就只能先排序，后指针扫描法或二分（时间n*logn，空间O（1）），或映射或hash（时间O（n），空间O（n））。时间或空间，必须牺牲一个，自个权衡吧。</li><li>综上，若是数组<strong>有序</strong>的情况下，优先考虑两个指针两端扫描法，以达到最佳的时（O（N）），空（O（1））效应。否则，如果要排序的话，时间复杂度最快当然是只能达到N*logN，空间O（1）则是不在话下。</li></ul><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><strong>代码：</strong></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">ok，在进入第二节之前，咱们先来实现思路5（这里假定数组已经是有序的），代码可以如下编写（两段代码实现）：</p><div nogutter=""  bg_cpp:nogutter"="" style="border: 1px dashed #999999; background-color: #f5f5f5; width: 687.0499877929688px;"><ol start="1" style="margin-bottom: 0px; padding-top: 5px; padding-bottom: 5px; position: relative;"><li style="line-height: 13px;"><span style="color: #999999;">//代码一</span>&nbsp;&nbsp;</li><li style="line-height: 13px;"><span style="color: #999999;">//O（N）</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">Pair&nbsp;findSum(<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;*s,<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;n,<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;x)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//sort(s,s+n);&nbsp;&nbsp;&nbsp;如果数组非有序的，那就事先排好序O（N*logN）&nbsp;&nbsp;&nbsp;</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;*begin=s;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;*end=s+n-1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">while</span>(begin&lt;end)&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//俩头夹逼，或称两个指针两端扫描法，很经典的方法，O（N）&nbsp;&nbsp;</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(*begin+*end&gt;x)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--end;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">else</span>&nbsp;<span style="color: #0000ff;">if</span>(*begin+*end&lt;x)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;++begin;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">else</span>&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;Pair(*begin,*end);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;Pair(-1,-1);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;</li><li style="line-height: 13px;"><span style="color: #999999;">//或者如下编写，</span>&nbsp;&nbsp;</li><li style="line-height: 13px;"><span style="color: #999999;">//代码二</span>&nbsp;&nbsp;</li><li style="line-height: 13px;"><span style="color: #999999;">//copyright@&nbsp;zhedahht&nbsp;&amp;&amp;&nbsp;yansha</span>&nbsp;&nbsp;</li><li style="line-height: 13px;"><span style="color: #999999;">//July、updated，2011.05.14。</span>&nbsp;&nbsp;</li><li style="line-height: 13px;"><span style="color: #2e8b57; font-weight: bold;">bool</span>&nbsp;find_num(<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;data[],&nbsp;unsigned&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;length,&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;sum,&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&amp;&nbsp;first_num,&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&amp;&nbsp;second_num)&nbsp;&nbsp;</li><li style="line-height: 13px;">{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(length&nbsp;&lt;&nbsp;1)&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;<span style="color: #0000ff;">true</span>;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;begin&nbsp;=&nbsp;0;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;end&nbsp;=&nbsp;length&nbsp;-&nbsp;1;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">while</span>(end&nbsp;&gt;&nbsp;begin)&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">long</span>&nbsp;current_sum&nbsp;=&nbsp;data[begin]&nbsp;+&nbsp;data[end];&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(current_sum&nbsp;==&nbsp;sum)&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;first_num&nbsp;=&nbsp;data[begin];&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;second_num&nbsp;=&nbsp;data[end];&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;<span style="color: #0000ff;">true</span>;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">else</span>&nbsp;<span style="color: #0000ff;">if</span>(current_sum&nbsp;&gt;&nbsp;sum)&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end--;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">else</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin++;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;<span style="color: #0000ff;">false</span>;&nbsp;&nbsp;</li><li style="line-height: 13px;">}&nbsp;&nbsp;</li></ol></div><p>&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><strong>扩展：</strong><br />1、如果在返回找到的两个数的同时，还要求你返回这两个数的位置列?<br />2、如果把题目中的要你寻找的两个数改为&#8220;多个数&#8221;，或任意个数列?（请看下面第二节）<br />3、二分查找时： left &lt;= right，right = middle - 1;left &lt; right，right = middle;</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;</p><blockquote style="font-family: Arial; line-height: 26px; background-color: #ffffff;"><p>//算法所操作的区间,是左闭右开区间,还是左闭右闭区间,这个区间,需要在循环初始化,<br />//循环体是否终止的判断中,以及每次修改left,right区间值这三个地方保持一致,否则就可能出错.</p><p>//二分查找实现一<br />int search(int array[], int n, int v)<br />{<br />&nbsp;&nbsp;&nbsp; int left, right, middle;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp; left = 0, right = n - 1;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp; while (left &lt;= right)<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; middle = left + (right-left)/2;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (array[middle] &gt; v)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; right = middle - 1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (array[middle] &lt; v)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; left = middle + 1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return middle;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;<br />&nbsp;&nbsp;&nbsp; return -1;<br />}</p><p>//二分查找实现二<br />int search(int array[], int n, int v)<br />{<br />&nbsp;&nbsp;&nbsp; int left, right, middle;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp; left = 0, right = n;<br />&nbsp;<br />&nbsp;&nbsp;&nbsp; while (left &lt; right)<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; middle = left + (right-left)/2;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (array[middle] &gt; v)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; right = middle;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (array[middle] &lt; v)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; left = middle + 1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return middle;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;<br />&nbsp;&nbsp;&nbsp; return -1;<br />}</p></blockquote><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><br /><span style="color: #800000;">第二节、寻找和为定值的多个数</span><br />第21题（数组）<br />2010年中兴面试题<br />编程求解：<br />输入两个整数 n 和 m，从数列1，2，3.......n 中 随意取几个数,<br />使其和等于 m ,要求将其中所有的可能组合列出来。</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><strong>解法一</strong><br />我想，稍后给出的程序已经足够清楚了，就是要注意到放n，和不放n个区别，即可，代码如下：</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"></p><div nogutter=""  bg_cpp:nogutter"="" style="border: 1px dashed #999999; background-color: #f5f5f5; width: 687.0499877929688px;"><ol start="1" style="margin-bottom: 0px; padding-top: 5px; padding-bottom: 5px; position: relative;"><li style="line-height: 13px;"><span style="color: #999999;">//&nbsp;21题递归方法</span>&nbsp;&nbsp;</li><li style="line-height: 13px;"><span style="color: #999999;">//copyright@&nbsp;July&nbsp;&amp;&amp;&nbsp;yansha</span>&nbsp;&nbsp;</li><li style="line-height: 13px;"><span style="color: #999999;">//July、yansha，updated。</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">#include&lt;list&gt;&nbsp;&nbsp;</li><li style="line-height: 13px;">#include&lt;iostream&gt;&nbsp;&nbsp;</li><li style="line-height: 13px;"><span style="color: #0000ff;">using</span>&nbsp;<span style="color: #0000ff;">namespace</span>&nbsp;std;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;</li><li style="line-height: 13px;">list&lt;<span style="color: #2e8b57; font-weight: bold;">int</span>&gt;list1;&nbsp;&nbsp;</li><li style="line-height: 13px;"><span style="color: #0000ff;">void</span>&nbsp;find_factor(<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;sum,&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;n)&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">{&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//&nbsp;递归出口</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(n&nbsp;&lt;=&nbsp;0&nbsp;||&nbsp;sum&nbsp;&lt;=&nbsp;0)&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//&nbsp;输出找到的结果</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>(sum&nbsp;==&nbsp;n)&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//&nbsp;反转list</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list1.reverse();&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>(list&lt;<span style="color: #2e8b57; font-weight: bold;">int</span>&gt;::iterator&nbsp;iter&nbsp;=&nbsp;list1.begin();&nbsp;iter&nbsp;!=&nbsp;list1.end();&nbsp;iter++)&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;*iter&nbsp;&lt;&lt;&nbsp;<span style="color: #009900;">"&nbsp;+&nbsp;"</span>;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;n&nbsp;&lt;&lt;&nbsp;endl;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list1.reverse();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;list1.push_front(n);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//典型的01背包问题</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;find_factor(sum-n,&nbsp;n-1);&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//放n，n-1个数填满sum-n</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;list1.pop_front();&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;find_factor(sum,&nbsp;n-1);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//不放n，n-1个数填满sum&nbsp;</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">}&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;</li><li style="line-height: 13px;"><span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;main()&nbsp;&nbsp;</li><li style="line-height: 13px;">{&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;sum,&nbsp;n;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;<span style="color: #009900;">"请输入你要等于多少的数值sum:"</span>&nbsp;&lt;&lt;&nbsp;endl;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;cin&nbsp;&gt;&gt;&nbsp;sum;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;<span style="color: #009900;">"请输入你要从1.....n数列中取值的n："</span>&nbsp;&lt;&lt;&nbsp;endl;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;cin&nbsp;&gt;&gt;&nbsp;n;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;<span style="color: #009900;">"所有可能的序列，如下："</span>&nbsp;&lt;&lt;&nbsp;endl;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;find_factor(sum,n);&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;0;&nbsp;&nbsp;</li><li style="line-height: 13px;">}&nbsp;&nbsp;</li></ol></div><p>&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><strong>解法二</strong><br />@zhouzhenren：<br />这个问题属于子集和问题（也是背包问题）。本程序采用 回溯法+剪枝<br />X数组是解向量，t=&#8721;(1,..,k-1)Wi*Xi, r=&#8721;(k,..,n)Wi<br />若t+Wk+W(k+1)&lt;=M,则Xk=true，递归左儿子(X1,X2,..,X(k-1),1)；否则剪枝；<br />若t+r-Wk&gt;=M &amp;&amp; t+W(k+1)&lt;=M,则置Xk=0，递归右儿子(X1,X2,..,X(k-1),0)；否则剪枝；<br />本题中W数组就是(1,2,..,n),所以直接用k代替WK值。</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">代码编写如下：</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"></p><div nogutter=""  bg_cpp:nogutter"="" style="border: 1px dashed #999999; background-color: #f5f5f5; width: 687.0499877929688px;"><ol start="1" style="margin-bottom: 0px; padding-top: 5px; padding-bottom: 5px; position: relative;"><li style="line-height: 13px;"><span style="color: #999999;">//copyright@&nbsp;2011&nbsp;zhouzhenren</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;</li><li style="line-height: 13px;"><span style="color: #999999;">//输入两个整数&nbsp;n&nbsp;和&nbsp;m，从数列1，2，3.......n&nbsp;中&nbsp;随意取几个数,</span>&nbsp;&nbsp;</li><li style="line-height: 13px;"><span style="color: #999999;">//使其和等于&nbsp;m&nbsp;,要求将其中所有的可能组合列出来。</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;</li><li style="line-height: 13px;">#include&nbsp;&lt;stdio.h&gt;&nbsp;&nbsp;</li><li style="line-height: 13px;">#include&nbsp;&lt;stdlib.h&gt;&nbsp;&nbsp;</li><li style="line-height: 13px;">#include&nbsp;&lt;memory.h&gt;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;</li><li style="line-height: 13px;"><span style="color: #999999;">/**&nbsp;</span>&nbsp;</li><li style="line-height: 13px;"><span style="color: #999999;">&nbsp;*&nbsp;输入t，&nbsp;r，&nbsp;尝试Wk</span>&nbsp;</li><li style="line-height: 13px;"><span style="color: #999999;">&nbsp;*/</span>&nbsp;&nbsp;</li><li style="line-height: 13px;"><span style="color: #0000ff;">void</span>&nbsp;sumofsub(<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;t,&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;k&nbsp;,<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;r,&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&amp;&nbsp;M,&nbsp;<span style="color: #2e8b57; font-weight: bold;">bool</span>&amp;&nbsp;flag,&nbsp;<span style="color: #2e8b57; font-weight: bold;">bool</span>*&nbsp;X)&nbsp;&nbsp;</li><li style="line-height: 13px;">{&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;X[k]&nbsp;=&nbsp;<span style="color: #0000ff;">true</span>;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//&nbsp;选第k个数</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>&nbsp;(t&nbsp;+&nbsp;k&nbsp;==&nbsp;M)&nbsp;<span style="color: #999999;">//&nbsp;若找到一个和为M，则设置解向量的标志位，输出解</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flag&nbsp;=&nbsp;<span style="color: #0000ff;">true</span>;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>&nbsp;(<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;i&nbsp;=&nbsp;1;&nbsp;i&nbsp;&lt;=&nbsp;k;&nbsp;++i)&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>&nbsp;(X[i]&nbsp;==&nbsp;1)&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(<span style="color: #009900;">"%d&nbsp;"</span>,&nbsp;i);&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(<span style="color: #009900;">"/n"</span>);&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">else</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//&nbsp;若第k+1个数满足条件，则递归左子树</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>&nbsp;(t&nbsp;+&nbsp;k&nbsp;+&nbsp;(k+1)&nbsp;&lt;=&nbsp;M)&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sumofsub(t&nbsp;+&nbsp;k,&nbsp;k&nbsp;+&nbsp;1,&nbsp;r&nbsp;-&nbsp;k,&nbsp;M,&nbsp;flag,&nbsp;X);&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//&nbsp;若不选第k个数，选第k+1个数满足条件，则递归右子树</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>&nbsp;((t&nbsp;+&nbsp;r&nbsp;-&nbsp;k&nbsp;&gt;=&nbsp;M)&nbsp;&amp;&amp;&nbsp;(t&nbsp;+&nbsp;(k+1)&nbsp;&lt;=&nbsp;M))&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X[k]&nbsp;=&nbsp;<span style="color: #0000ff;">false</span>;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sumofsub(t,&nbsp;k&nbsp;+&nbsp;1,&nbsp;r&nbsp;-&nbsp;k,&nbsp;M,&nbsp;flag,&nbsp;X);&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 13px;">}&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;</li><li style="line-height: 13px;"><span style="color: #0000ff;">void</span>&nbsp;search(<span style="color: #2e8b57; font-weight: bold;">int</span>&amp;&nbsp;N,&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&amp;&nbsp;M)&nbsp;&nbsp;</li><li style="line-height: 13px;">{&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//&nbsp;初始化解空间</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">bool</span>*&nbsp;X&nbsp;=&nbsp;(<span style="color: #2e8b57; font-weight: bold;">bool</span>*)malloc(<span style="color: #0000ff;">sizeof</span>(<span style="color: #2e8b57; font-weight: bold;">bool</span>)&nbsp;*&nbsp;(N+1));&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;memset(X,&nbsp;<span style="color: #0000ff;">false</span>,&nbsp;<span style="color: #0000ff;">sizeof</span>(<span style="color: #2e8b57; font-weight: bold;">bool</span>)&nbsp;*&nbsp;(N+1));&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;sum&nbsp;=&nbsp;(N&nbsp;+&nbsp;1)&nbsp;*&nbsp;N&nbsp;*&nbsp;0.5f;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>&nbsp;(1&nbsp;&gt;&nbsp;M&nbsp;||&nbsp;sum&nbsp;&lt;&nbsp;M)&nbsp;<span style="color: #999999;">//&nbsp;预先排除无解情况</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(<span style="color: #009900;">"not&nbsp;found/n"</span>);&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">bool</span>&nbsp;f&nbsp;=&nbsp;<span style="color: #0000ff;">false</span>;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;sumofsub(0,&nbsp;1,&nbsp;sum,&nbsp;M,&nbsp;f,&nbsp;X);&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>&nbsp;(!f)&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(<span style="color: #009900;">"not&nbsp;found/n"</span>);&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;free(X);&nbsp;&nbsp;</li><li style="line-height: 13px;">}&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;</li><li style="line-height: 13px;"><span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;main()&nbsp;&nbsp;</li><li style="line-height: 13px;">{&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;N,&nbsp;M;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;printf(<span style="color: #009900;">"请输入整数N和M/n"</span>);&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;scanf(<span style="color: #009900;">"%d%d"</span>,&nbsp;&amp;N,&nbsp;&amp;M);&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;search(N,&nbsp;M);&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;0;&nbsp;&nbsp;</li><li style="line-height: 13px;">}&nbsp;&nbsp;</li></ol></div><p>&nbsp;</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><strong>扩展：</strong></p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">1、从一列数中筛除尽可能少的数使得从左往右看，这些数是从小到大再从大到小的（网易）。</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">2、有两个序列a,b，大小都为n,序列元素的值任意整数，无序；<br />要求：通过交换a,b中的元素，使[序列a元素的和]与[序列b元素的和]之间的差最小。<br />例如:&nbsp;&nbsp;<br />var a=[100,99,98,1,2, 3];<br />var b=[1, 2, 3, 4,5,40];（<a href="http://blog.csdn.net/v_JULY_v/archive/2010/12/06/6057286.aspx" target="_blank" style="color: #336699; text-decoration: initial;"><strong><span style="color: #3366ff;">微软100题</span></strong></a>第32题）。</p><blockquote style="font-family: Arial; line-height: 26px; background-color: #ffffff;"><p><span style="font-size: 12px;">&nbsp;&nbsp;&nbsp; @well：[fairywell]:<br /></span><span style="font-size: 12px;"><strong>给出扩展问题 1 的一个解法：<br /></strong>1、从一列数中筛除尽可能少的数使得从左往右看，这些数是从小到大再从大到小的（网易）。<br />双端 LIS 问题，用 DP 的思想可解，目标规划函数 max{ b[i] + c[i] - 1 }, 其中 b[i] 为从左到右， 0 ~ i 个数之间满足递增的数字个数； c[i] 为从右到左， n-1 ~ i 个数之间满足递增的数字个数。最后结果为 n - max + 1。其中 DP 的时候，可以维护一个 inc[] 数组表示递增数字序列，inc[i] 为从小到大第 i 大的数字，然后在计算 b[i] c[i] 的时候使用二分查找在 inc[] 中找出区间 inc[0] ~ inc[i-1] 中小于 a[i] 的元素个数（low）。<br />源代码如下：<br /></span></p><div nogutter=""  bg_cpp:nogutter"="" style="border: 1px dashed #999999; background-color: #f5f5f5; width: 607.8499755859375px;"><ol start="1" style="margin-bottom: 0px; padding-top: 5px; padding-bottom: 5px; position: relative;"><li style="line-height: 13px;"><span style="color: #999999;">/**</span>&nbsp;</li><li style="line-height: 13px;"><span style="color: #999999;">*&nbsp;The&nbsp;problem:</span>&nbsp;</li><li style="line-height: 13px;"><span style="color: #999999;">*&nbsp;从一列数中筛除尽可能少的数使得从左往右看，这些数是从小到大再从大到小的（网易）。</span>&nbsp;</li><li style="line-height: 13px;"><span style="color: #999999;">*&nbsp;use&nbsp;binary&nbsp;search,&nbsp;perhaps&nbsp;you&nbsp;should&nbsp;compile&nbsp;it&nbsp;with&nbsp;-std=c99</span>&nbsp;</li><li style="line-height: 13px;"><span style="color: #999999;">*&nbsp;fairywell&nbsp;2011</span>&nbsp;</li><li style="line-height: 13px;"><span style="color: #999999;">*/</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">#include&nbsp;&lt;stdio.h&gt;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;</li><li style="line-height: 13px;">#define&nbsp;MAX_NUM&nbsp;&nbsp;&nbsp;&nbsp;(1U&lt;&lt;31)&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;</li><li style="line-height: 13px;"><span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">main()&nbsp;&nbsp;</li><li style="line-height: 13px;">{&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">int</span>&nbsp;i,&nbsp;n,&nbsp;low,&nbsp;high,&nbsp;mid,&nbsp;max;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;printf(<span style="color: #009900;">"Input&nbsp;how&nbsp;many&nbsp;numbers&nbsp;there&nbsp;are:&nbsp;"</span>);&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;scanf(<span style="color: #009900;">"%d/n"</span>,&nbsp;&amp;n);&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">/*&nbsp;a[]&nbsp;holds&nbsp;the&nbsp;numbers,&nbsp;b[i]&nbsp;holds&nbsp;the&nbsp;number&nbsp;of&nbsp;increasing&nbsp;numbers</span>&nbsp;</li><li style="line-height: 13px;"><span style="color: #999999;">&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;from&nbsp;a[0]&nbsp;to&nbsp;a[i],&nbsp;c[i]&nbsp;holds&nbsp;the&nbsp;number&nbsp;of&nbsp;increasing&nbsp;numbers</span>&nbsp;</li><li style="line-height: 13px;"><span style="color: #999999;">&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;from&nbsp;a[n-1]&nbsp;to&nbsp;a[i]</span>&nbsp;</li><li style="line-height: 13px;"><span style="color: #999999;">&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;inc[]&nbsp;holds&nbsp;the&nbsp;increasing&nbsp;numbers</span>&nbsp;</li><li style="line-height: 13px;"><span style="color: #999999;">&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;VLA&nbsp;needs&nbsp;c99&nbsp;features,&nbsp;compile&nbsp;with&nbsp;-stc=c99</span>&nbsp;</li><li style="line-height: 13px;"><span style="color: #999999;">&nbsp;&nbsp;&nbsp;&nbsp;*/</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #2e8b57; font-weight: bold;">double</span>&nbsp;a[n],&nbsp;b[n],&nbsp;c[n],&nbsp;inc[n];&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;printf(<span style="color: #009900;">"Please&nbsp;input&nbsp;the&nbsp;numbers:/n"</span>);&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>&nbsp;(i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;n;&nbsp;++i)&nbsp;scanf(<span style="color: #009900;">"%lf"</span>,&nbsp;&amp;a[i]);&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//&nbsp;update&nbsp;array&nbsp;b&nbsp;from&nbsp;left&nbsp;to&nbsp;right</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>&nbsp;(i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;n;&nbsp;++i)&nbsp;inc[i]&nbsp;=&nbsp;(unsigned)&nbsp;MAX_NUM;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//b[0]&nbsp;=&nbsp;0;</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>&nbsp;(i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;n;&nbsp;++i)&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;low&nbsp;=&nbsp;0;&nbsp;high&nbsp;=&nbsp;i;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">while</span>&nbsp;(low&nbsp;&lt;&nbsp;high)&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mid&nbsp;=&nbsp;low&nbsp;+&nbsp;(high-low)*0.5;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>&nbsp;(inc[mid]&nbsp;&lt;&nbsp;a[i])&nbsp;low&nbsp;=&nbsp;mid&nbsp;+&nbsp;1;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">else</span>&nbsp;high&nbsp;=&nbsp;mid;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b[i]&nbsp;=&nbsp;low&nbsp;+&nbsp;1;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inc[low]&nbsp;=&nbsp;a[i];&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//&nbsp;update&nbsp;array&nbsp;c&nbsp;from&nbsp;right&nbsp;to&nbsp;left</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>&nbsp;(i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;n;&nbsp;++i)&nbsp;inc[i]&nbsp;=&nbsp;(unsigned)&nbsp;MAX_NUM;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999999;">//c[0]&nbsp;=&nbsp;0;</span>&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>&nbsp;(i&nbsp;=&nbsp;n-1;&nbsp;i&nbsp;&gt;=&nbsp;0;&nbsp;--i)&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;low&nbsp;=&nbsp;0;&nbsp;high&nbsp;=&nbsp;i;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">while</span>&nbsp;(low&nbsp;&lt;&nbsp;high)&nbsp;{&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mid&nbsp;=&nbsp;low&nbsp;+&nbsp;(high-low)*0.5;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>&nbsp;(inc[mid]&nbsp;&lt;&nbsp;a[i])&nbsp;low&nbsp;=&nbsp;mid&nbsp;+&nbsp;1;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">else</span>&nbsp;high&nbsp;=&nbsp;mid;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c[i]&nbsp;=&nbsp;low&nbsp;+&nbsp;1;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inc[low]&nbsp;=&nbsp;a[i];&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;max&nbsp;=&nbsp;0;&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">for</span>&nbsp;(i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;n;&nbsp;++i&nbsp;)&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">if</span>&nbsp;(b[i]+c[i]&nbsp;&gt;&nbsp;max)&nbsp;max&nbsp;=&nbsp;b[i]&nbsp;+&nbsp;c[i];&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(<span style="color: #009900;">"%d&nbsp;number(s)&nbsp;should&nbsp;be&nbsp;erased&nbsp;at&nbsp;least./n"</span>,&nbsp;n+1-max);&nbsp;&nbsp;</li><li style="line-height: 13px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff;">return</span>&nbsp;0;&nbsp;&nbsp;</li><li style="line-height: 13px;">}&nbsp;&nbsp;</li></ol></div><p>&nbsp;</p><p><span style="font-size: 12px;">@yansha：fairywell的程序很赞，时间复杂度O(nlogn)，这也是我能想到的时间复杂度最优值了。不知能不能达到O(n)。</span></p></blockquote><blockquote style="font-family: Arial; line-height: 26px; background-color: #ffffff;"><p><strong><span style="font-size: 12px;">扩展题第2题</span></strong></p><p><span style="font-size: 12px;">当前数组a和数组b的和之差为<br />&nbsp;&nbsp;&nbsp; A = sum(a) - sum(b)</span></p><p><span style="font-size: 12px;">a的第i个元素和b的第j个元素交换后，a和b的和之差为<br />&nbsp;&nbsp;&nbsp; A' = sum(a) - a[i] + b[j] - （sum(b) - b[j] + a[i])<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = sum(a) - sum(b) - 2 (a[i] - b[j])<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = A - 2 (a[i] - b[j])</span></p><p><span style="font-size: 12px;">设x = a[i] - b[j]，得<br />&nbsp;&nbsp;&nbsp; |A| - |A'| = |A| - |A-2x|</span></p><p><span style="font-size: 12px;">&nbsp;&nbsp;&nbsp; 假设A &gt; 0,</span></p><p><span style="font-size: 12px;">&nbsp;&nbsp;&nbsp; 当x 在 (0,A)之间时，做这样的交换才能使得交换后的a和b的和之差变小，x越接近A/2效果越好,<br />&nbsp;&nbsp;&nbsp; 如果找不到在(0,A)之间的x，则当前的a和b就是答案。</span></p><p><span style="font-size: 12px;">所以算法大概如下：<br />&nbsp;&nbsp;&nbsp; 在a和b中寻找使得x在(0,A)之间并且最接近A/2的i和j，交换相应的i和j元素，重新计算A后，重复前面的步骤直至找不到(0,A)之间的x为止。&nbsp;</span></p><p><span style="font-size: 12px;">接上，@yuan：<br />a[i]-b[j]要接近A/2，则可以这样想，<br />我们可以对于a数组的任意一个a[k],在数组b中找出与a[k]-C最接近的数（C就是常数，也就是0.5*A）<br />这个数要么就是a[k]-C，要么就是比他稍大，要么比他稍小，所以可以要二分查找。</span></p><p><span style="font-size: 12px;">查找最后一个小于等于a[k]-C的数和第一个大于等于a[k]-C的数，<br />然后看哪一个与a[k]-C更加接近，所以T(n) = nlogn。</span></p><p><span style="font-size: 12px;">除此之外，受本文读者<span style="color: #666666; font-family: Arial, Console, Verdana, 'Courier New'; line-height: 14px;">xiafei1987128启示，</span>有朋友在stacoverflow上也问过一个类似的题，:-)，见此：<a href="http://stackoverflow.com/questions/9047908/swap-the-elements-of-two-sequences-such-that-the-difference-of-the-element-sums" target="_blank" style="color: #336699; text-decoration: initial;"><span style="font-family: 'Comic Sans MS';">http://stackoverflow.com/questions/9047908/swap-the-elements-of-two-sequences-such-that-the-difference-of-the-element-sums</span></a>。感兴趣的可以看看。</span></p></blockquote><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">本章完。</p><hr style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;</p><blockquote style="font-family: Arial; line-height: 26px; background-color: #ffffff;"><p><span style="font-size: 12px;">程序员面试题狂想曲-tctop（the crazy thinking of programers）的修订wiki（<a href="http://tctop.wikispaces.com/" target="_blank" style="color: #336699; text-decoration: initial;"><span style="color: #002d93;"><strong>http://tctop.wikispaces.com/</strong></span></a></span><span style="font-size: 12px;">）已建立，我们急切的想得到读者的反馈，意见，建议，以及更好的思路，算法，和代码优化的建议。所以，</span></p><p><span style="font-size: 12px;">&#8226;如果你发现了狂想曲系列中的任何一题，任何一章（<a title="http://blog.csdn.net/v_JULY_v/category/784066.aspx" href="http://t.cn/hgVPmH" target="_blank" style="color: #336699; text-decoration: initial;"><span style="color: #0082cb;"><strong>http://t.cn/hgVPmH</strong></span></a></span><span style="font-size: 12px;">）中的错误，问题，与漏洞，欢迎告知给我们，我们将感激不尽，同时，免费赠送本blog内的全部博文集锦的CHM文件1期；<br />&#8226;如果你能对狂想曲系列的创作提供任何建设性意见，或指导，欢迎反馈给我们，并真诚邀请您加入到狂想曲的wiki修订工作中；<br />&#8226;如果你是编程高手，对狂想曲的任何一章有自己更好的思路，或算法，欢迎加入狂想曲的创作组，以为千千万万的读者创造更多的价值，更好的服务。<br />Ps：狂想曲tctop的wiki修订地址为：<a href="http://tctop.wikispaces.com/" target="_blank" style="color: #336699; text-decoration: initial;"><span style="color: #002d93;"><strong>http://tctop.wikispaces.com/</strong></span></a></span><span style="font-size: 12px;">。欢迎围观，更欢迎您加入到狂想曲的创作或wiki修订中。</span>&nbsp;</p></blockquote><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><span style="color: #800000;"><strong>版权所有，本人对本blog内所有任何内容享有版权及著作权。实要转载，请以链接形式注明出处。</strong></span></p><img src ="http://www.cppblog.com/mysileng/aggbug/195849.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-11-30 21:09 <a href="http://www.cppblog.com/mysileng/archive/2012/11/30/195849.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序员编程艺术-----第四章-----现场编写类似strstr/strcpy/strpbrk的函数</title><link>http://www.cppblog.com/mysileng/archive/2012/11/21/195477.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Wed, 21 Nov 2012 11:04:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/11/21/195477.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/195477.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/11/21/195477.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/195477.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/195477.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;第四章、现场编写类似strstr/strcpy/strpbrk的函数&nbsp;&nbsp;&nbsp;&nbsp;作者：July。&nbsp;&nbsp;&nbsp; 说明：&nbsp;如果在博客中代码使用了\n，csdn blog系统将会自动回给我变成/n。据后续验证，可能是原来旧bl...&nbsp;&nbsp;<a href='http://www.cppblog.com/mysileng/archive/2012/11/21/195477.html'>阅读全文</a><img src ="http://www.cppblog.com/mysileng/aggbug/195477.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-11-21 19:04 <a href="http://www.cppblog.com/mysileng/archive/2012/11/21/195477.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序员编程艺术-----第三章续-----Top K算法问题的实现</title><link>http://www.cppblog.com/mysileng/archive/2012/11/21/195473.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Wed, 21 Nov 2012 09:21:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/11/21/195473.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/195473.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/11/21/195473.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/195473.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/195473.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; 程序员编程艺术：第三章续、Top K算法问题的实现&nbsp;&nbsp;&nbsp; 作者：July，zhouzhenren，yansha。&nbsp;&nbsp;&nbsp; 致谢：微软100题实现组，狂想曲创作组。&nbsp;&nb...&nbsp;&nbsp;<a href='http://www.cppblog.com/mysileng/archive/2012/11/21/195473.html'>阅读全文</a><img src ="http://www.cppblog.com/mysileng/aggbug/195473.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-11-21 17:21 <a href="http://www.cppblog.com/mysileng/archive/2012/11/21/195473.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序员编程艺术-----第三章-----寻找最小的k个数</title><link>http://www.cppblog.com/mysileng/archive/2012/11/20/195436.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Tue, 20 Nov 2012 13:56:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/11/20/195436.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/195436.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/11/20/195436.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/195436.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/195436.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;程序员编程艺术：第三章、寻找最小的k个数作者：July。时间：二零一一年四月二十八日。致谢：litaoye，&nbsp;strugglever，yansha，luuillu，Sorehead，及狂想曲创作组。微博：http://weibo.com/j...&nbsp;&nbsp;<a href='http://www.cppblog.com/mysileng/archive/2012/11/20/195436.html'>阅读全文</a><img src ="http://www.cppblog.com/mysileng/aggbug/195436.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-11-20 21:56 <a href="http://www.cppblog.com/mysileng/archive/2012/11/20/195436.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序员编程艺术-----第二章-----字符串是否包含及匹配/查找/转换/拷贝问题</title><link>http://www.cppblog.com/mysileng/archive/2012/11/19/195347.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Mon, 19 Nov 2012 03:43:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/11/19/195347.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/195347.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/11/19/195347.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/195347.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/195347.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;程序员编程艺术：第二章、字符串是否包含及匹配/查找/转换/拷贝问题作者：July，yansha。时间：二零一一年四月二十三日。致谢：老梦，nossiac，Hession，Oliver，luuillu，雨翔，啊菜，及微软10...&nbsp;&nbsp;<a href='http://www.cppblog.com/mysileng/archive/2012/11/19/195347.html'>阅读全文</a><img src ="http://www.cppblog.com/mysileng/aggbug/195347.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-11-19 11:43 <a href="http://www.cppblog.com/mysileng/archive/2012/11/19/195347.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序员编程艺术-----第一章-----左旋转字符串</title><link>http://www.cppblog.com/mysileng/archive/2012/11/18/195323.html</link><dc:creator>鑫龙</dc:creator><author>鑫龙</author><pubDate>Sun, 18 Nov 2012 08:39:00 GMT</pubDate><guid>http://www.cppblog.com/mysileng/archive/2012/11/18/195323.html</guid><wfw:comment>http://www.cppblog.com/mysileng/comments/195323.html</wfw:comment><comments>http://www.cppblog.com/mysileng/archive/2012/11/18/195323.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mysileng/comments/commentRss/195323.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mysileng/services/trackbacks/195323.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;第一章、左旋转字符串作者：July，yansha。时间：二零一一年四月十四日。微博：http://weibo.com/julyweibo。出处：http://blog.csdn.net/v_JULY_v。-----------------------------...&nbsp;&nbsp;<a href='http://www.cppblog.com/mysileng/archive/2012/11/18/195323.html'>阅读全文</a><img src ="http://www.cppblog.com/mysileng/aggbug/195323.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mysileng/" target="_blank">鑫龙</a> 2012-11-18 16:39 <a href="http://www.cppblog.com/mysileng/archive/2012/11/18/195323.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>