程序员编程艺术.docx

上传人:b****8 文档编号:9081904 上传时间:2023-02-03 格式:DOCX 页数:38 大小:33.43KB
下载 相关 举报
程序员编程艺术.docx_第1页
第1页 / 共38页
程序员编程艺术.docx_第2页
第2页 / 共38页
程序员编程艺术.docx_第3页
第3页 / 共38页
程序员编程艺术.docx_第4页
第4页 / 共38页
程序员编程艺术.docx_第5页
第5页 / 共38页
点击查看更多>>
下载资源
资源描述

程序员编程艺术.docx

《程序员编程艺术.docx》由会员分享,可在线阅读,更多相关《程序员编程艺术.docx(38页珍藏版)》请在冰豆网上搜索。

程序员编程艺术.docx

程序员编程艺术

程序员编程艺术

 

程序员编程艺术第一二十七章集锦与总结

教你如何编程

作者July编程艺术室

时间comcom

出处httpcomv_JULY_v

声明版权所有侵权定究

本文档制作者有鱼comCEO吴超花明月暗

前言

围绕面试算法编程三个主题的程序员编程艺术系列简称TAOPP系列从

今年4月写第一篇起至今快有一年近1年的创作中写了二十七章共计22篇文章

这是本人的第4大原创作品不过与之前微软面试100题系列红黑树系列及十三个经

典算法研究系列相比编程艺术系列的某些篇文章的作者除了我本人自己或多或少还得到

了不少朋友的支持我把这些朋友组织起来成立了一个工作室它的名字叫做编程艺术室

编程艺术系列最初名为程序员面试题狂想曲即为面试服务后来随着加入与我一起创

作的人越来越多我们逐渐意识到为面试服务不应该成为我们最终或最主要的目的而应

该注重提高广大初学者的编程能力以及如何运用编程技巧和高效的算法解决实际应用问

题这才是计算机科学与编程的本质于是我们便把程序员面试题狂想曲系列更名为程序

员编程艺术系列然后把狂想曲创作组确定为编程艺术室并提出了我们的宗旨即如下

编程艺术室致力于以下三点工作

1针对一个问题不断寻找更高效的算法并予以编程实现

2解决实际中会碰到的应用问题

3经典算法的研究与实现

总体突出一点编程如何高效的编程解决实际问题

刚开始的时候我们是不敢给自己戴艺术这个高帽子的因为艺术的提炼是一个非常非

常艰难的过程且我们全部都是一群庸人但是我们很想也非常乐意接受这个挑战所以

一边带着万分的惶恐一边认真细心的创作每一章等到发布后再对每一章任何一个细节

1

仔细推敲与琢磨反复思考反复修正反复完善绝不轻易放过任何一个问题漏洞和

bug但即便如此仍然冒出了很多的问题幸运的是有广大的读者朋友们对编程艺术系

列和我们给予热心的指导与优化建议更重要的是他们还耐心细致的对编程艺术系列提出了

非常多的且异常宝贵的批评指正与修订完善的意见

没有编程艺术室全部人员的加入创作编程艺术系列将比现在所呈现在大家面前的还要

糟糕至少我个人现在是这么认为的而如果没有众多网友朋友们的修正与完善编程

艺术系列将更显不足从而失去它本身该有的持久动力与明天所以非常感谢所有热心的

朋友给予编程艺术系列所有的指导和意见你们的反馈给了我们的创作很大很大的帮助同

时也感谢本社区编辑的推荐非常感谢最后恳请广大读者对编程艺术系列继续监督

并随时予以批评指正我们不能残留任何一个bug因为编程艺术系列最后可能要写到第

六十章谢谢

ok以下是已经写了的编程艺术系列的前二十七章共21篇文章希望你能从中感受到

编程的技巧与乐趣点击链接即可跳转到相应页面

无私分享造福天下

第一章左旋转字符串4

第二章字符串是否包含及相关问题扩展34

第三章寻找最小的k个数63

第三章续TopK算法问题的实现107

第三章再续快速选择SELECT算法的深入分析与实现148

第三章三续求数组中给定下标区间内的第K小大元素167

第四章现场编写类似strstrstrcpystrpbrk的函数178

第五章寻找满足条件的两个或多个数195

第六章亲和数问题--求解500万以内的亲和数208

第七章求连续子数组的最大和215

第八章从头至尾漫谈虚函数222

第九章闲话链表追赶问题237

第十章如何给107个数据量的磁盘文件排序246

第十一章最长公共子序列LCS问题280

第十二十五章中签概率IP访问次数回文等问题初稿291

第十六第二十章全排列跳台阶奇偶排序第一个只出现一次等问题305

2

第二十一二十二章出现次数超过一半的数字最短摘要的生成322

第二十三四章杨氏矩阵查找倒排索引关键词Hash不重复编码实践340

第二十五章二分查找实现JonBentley90程序员无法正确实现363

第二十六章基于给定的文档生成倒排索引的编码与实践366

第二十七章不改变正负数之间相对顺序重新排列数组时间ON空间O1393

编程艺术室

编程艺术系列已经发布的上二十七章仍有很多很多的问题与不足但永久勘误永久

优化如果读者朋友对编程艺术系列任何一章有任何问题和建议或者发现了以上任何一

章的问题错误漏洞和bug欢迎及时反馈给我们我们将感激不尽当然如果有兴

趣我们也欢迎您加入我们--编程艺术室

1编程能力较强

2有一定的业余时间

3工作经验越长越好能力出众的在读研究生或ACM人员也可以考虑

4愿意分享平时工作中的项目经验或性能优化建议

5热爱算法者优先

符合以上条件的朋友欢迎加入编程艺术室有意者可给我zhoulei0907yahoocn投一

篇稿子稿子主题内容形式不限只要你觉得自己能写出像已有的27章那样的文章便

可投稿审阅之后邀请加入以为大家创造更多的价值更好的服务谢谢

版权所有XX严禁用于任何商业用途违者定究法律责任

特别提醒

本编程艺术系列文档中有任何一处错误bug或漏洞读者朋友一经发现欢迎随时

来信指导或blog内留言评论我将感激不尽

我的联系方式如下

邮箱zhoulei0907yahoocn

微博httpweibocomjulyweibo

Bloghttpcomv_JULY_v

本结构之法算法之道blog若无意外永久更新永久勘误

感谢关注本编程艺术系列的读者朋友们感谢所有编程艺术室内的朋友咱们blog上

第二十八章再见

3

第一章左旋转字符串

作者Julyyansha

时间二零一一年四月十四日

说明狂想曲有三层意思1思绪纷飞行文杂乱无章想到什么记下什么2简单问题深入

化复杂问题精细化不惧汪洋不惧艰深洋洋洒洒纵横千里3依托一道面试题展开来思维放任

不羁逐步深入细致入微反复修正绝不含糊以期给读者一个彻彻底底明明白白的交待原为狂想

曲现在已改为编程艺术系列

微博httpweibocomjulyweibo

出处httpcomv_JULY_v

 

前言

第一节左旋转字符串

第二节两个指针逐步翻转

第三节通过递归转换缩小问题之规模

第四节stlrotate算法的步步深入

第五节总结

一个懒散的午夜程序员躺在椅子上静静点上一支烟瞅着屏幕上那一行一行如行云

流水般的代码赏心悦目渐觉困意便慢慢闭上了俩眼养神

而后冥冥中房间里似缓缓响起一首钢琴曲叫不出名字却铿锵有力且清脆无比忽

而激荡忽而平静激荡处如波涛翻滚怒洋咆哮平静处如潺潺流水鸟语花香

半响程序员突然睁开双眼关掉编译器打开记事本信笔由缰急速记录下他那杂

乱无章和奇特跳跃的思绪他怕此刻不赶紧记下来以后风吹云散于是世间就有

了程序员面试题狂想曲一乐章的诞生

此曲终日弹奏绵绵不绝终至广为流传飘进了千万人的耳中余音不去

前言

4

本人整理微软等公司面试100题系列包括原题整理资源上传帖子维护答案整理

勘误修正与优化工作包括后续全新整理的80道总计180道面试题已有半年的时间

关于这180道面试题的一切详情请参见横空出世席卷Csdn[评微软等数据结构

算法面试180题]

一直觉得这180道题中的任何一题都值得自己反复思考反复研究不断修正不断

优化之前的答案整理由于时间仓促加之受最开始的认识局限更兼水平有限所以这

180道面试题的答案有很多问题都值得进一步商榷与完善

特此想针对这180道面试题再写一个系列叫做程序员编程艺术系列如你所见

我一般确定要写成一个系列的东西一般都会永久写下去的

他似风儿一般奔跑很多人渐渐的停下来了而只有他一直在飞一直在飞

ok本次程序员编程艺术系列以之前本人最初整理的微软面试100题中的第26题左

旋转字符串为开篇希望就此问题进行彻底而深入的阐述然以下所有任何代码仅仅只是

全部测试正确了而已还有很多的优化工作要做欢迎任何人不吝赐教谢谢

第一节左旋转字符串

题目描述

定义字符串的左旋转操作把字符串前面的若干个字符移动到字符串的尾部

如把字符串abcdef左旋转2位得到字符串cdefab

请实现字符串左旋转的函数要求对长度为n的字符串操作的时间复杂度为

On空间复杂度为O1

编程之美上有这样一个类似的问题咱们先来看一下

设计一个算法把一个含有N个元素的数组循环右移K位要求时间复杂度为ON

且只允许使用两个附加变量

分析

5

我们先试验简单的办法可以每次将数组中的元素右移一位循环K次

abcd1234→4abcd123→34abcd12→234abcd1→1234abcd

RightShiftintarrintNintK

whileK--

inttarr[N-1]

forintiN-1i0i--

arr[i]arr[i-1]

arr[0]t

虽然这个算法可以实现数组的循环右移但是算法复杂度为OKN不符合题目的要

求要继续探索

假如数组为abcd1234循环右移4位的话我们希望到达的状态是1234abcd

不妨设K是一个非负的整数当K为负整数的时候右移K位相当于左移-K位

左移和右移在本质上是一样的

解法一

大家开始可能会有这样的潜在假设KN事实上很多时候也的确是这样的但严格来说

我们不能用这样的惯性思维来思考问题

尤其在编程的时候全面地考虑问题是很重要的K可能是一个远大于N的整数在这个

时候上面的解法是需要改进的

仔细观察循环右移的特点不难发现每个元素右移N位后都会回到自己的位置上因此

如果KN右移K-N之后的数组序列跟右移K位的结果是一样的

进而可得出一条通用的规律

右移K位之后的情形跟右移KKN位之后的情形一样如代码清单2-34所示

代码清单2-34

RightShiftintarrintNintK

KN

whileK--

6

inttarr[N-1]

forintiN-1i0i--

arr[i]arr[i-1]

arr[0]t

可见增加考虑循环右移的特点之后算法复杂度降为ON2这跟K无关与题目

的要求又接近了一步但时间复杂度还不够低接下来让我们继续挖掘循环右移前后数组

之间的关联

解法二

假设原数组序列为abcd1234要求变换成的数组序列为1234abcd即循环右移了4位

比较之后不难看出其中有两段的顺序是不变的1234和abcd可把这两段看成两个整

体右移K位的过程就是把数组的两部分交换一下

变换的过程通过以下步骤完成

逆序排列abcdabcd1234→dcba1234

逆序排列1234dcba1234→dcba4321

全部逆序dcba4321→1234abcd

伪代码可以参考清单2-35

代码清单2-35

Reverseintarrintbinte

forbebe--

inttemparr[e]

arr[e]arr[b]

arr[b]temp

RightShiftintarrintNintk

KN

Reversearr0N–K-1

ReversearrN-KN-1

7

Reversearr0N-1

这样我们就可以在线性时间内实现右移操作了

稍微总结下

编程之美上

限制书中思路的根本原因是题目要求且只允许使用两个附加变量去掉这个限制

思路便可如泉喷涌

1第一个想法是一个字符一个字符的右移所以复杂度为ONK

2后来它改进了通过这条规律右移K位之后的情形跟右移KKN位之后的情

形一样

复杂度为ON2

3直到最后它才提出三次翻转的算法得到线性复杂度

下面你将看到本章里我们的做法是

1三次翻转直接线性

2两个指针逐步翻转线性

3stl的rotate算法线性

好的现在回到咱们的左旋转字符串的问题中来对于这个左旋转字符串的问题咱们可

以如下这样考虑

11思路一

对于这个问题咱们换一个角度可以这么做

将一个字符串分成两部分X和Y两个部分在字符串上定义反转的操作XT即把X的

所有字符反转如X"abc"那么XT"cba"那么我们可以得到下面的结论

XTYTTYX显然我们这就可以转化为字符串的反转的问题了

不是么ok就拿abcdef这个例子来说非常简短的三句请细看一看就懂

1首先分为俩部分XabcYdef

2X-XTabc-cbaY-YTdef-fed

3XTYTTYXcbafed-defabc即整个翻转

我想这下你应该了然了

然后代码可以这么写已测试正确

1Copyright小桥流水July

8

2c代码实现已测试正确

3httpsmallbrcom20110313100E9A298

4_21-E5B7A6E6978BE8BDACE5AD97E7ACA6E4B8B26>html

5Julyupdatedcom

6include

7include

8

9charinvertcharstartcharend

10

11chartmpptmpstart

12whilestartNULLendNULLstartend

13

14tmpstart

15startend

16endtmp

17start

18end--

19

20returnptmp

21

22

23charleftcharsintpospos为要旋转的字符个数或长度下面主函数测试中

pos3

24

25intlenstrlens

26invertsspos-1如上X-XT即abc-cba

27invertsposslen-1如上Y-YT即def-fed

28invertsslen-1如上整个翻转XTYTTYX

即cbafed-defabc

29returns

30

31

32intmain

33

34chars[]"abcdefghij"

35putslefts3

36return0

37

12答案V03版中第26题勘误

之前的答案V03版[第21-40题答案]中第26题贴的答案有误那段代码的问题最

早是被网友Sorehead给指出来的

9

第二十六题

楼主的思路确实很巧妙我真没想到还有这种方法学习了

不过楼主代码中存在问题主要是条件判断部分

函数LeftRotateString中ifnLength0n0nnLength

函数ReverseString中ifpStartNULLpEndNULL

当时以答案整理因时间仓促及最开始考虑问题不够周全为由没有深入细看下去

后来朋友达摩流浪者再次指出了上述代码的问题

26题这句ifnLength0n0nnLength有问题吧

还有一句应该是ifpStartNULLpEndNULL吧

而后修改如下已测试正确

1zhedahht

2Julykupdated

3copyrightcombyJuly

4引用请注明原作者出处

5include

6include

7usingnamespacestd

8

9voidSwapcharacharb特此把交换函数独立抽取出来当然不排除会

有人认为此为多此一举

10

11chartempa

12ab

13btemp

14

15

16ReversethestringbetweenpStartandpEnd

17voidReverseStringcharpStartcharpEnd

18

19ifpStart0pEnd0

20这句也可以是ifpStartNULLpEndNULL

21

22whilepStartpEnd

23

24SwappStartpEnd交换

25

26pStart

27pEnd--

10

28

29

30

31

32Movethefirstncharsinastringtoitsend

33charLeftRotateStringcharpStrunsignedintn

34

35ifpStrNULL

36

37intnLengthstatic_caststrlenpStr

38ifnLength0n0nnLengthn可以0也可以说不该

0

39nLength是整个字符串的长度n是左边的一部分所以应该是

nnLength

40之前上传的答案代码就错在这里最初的为nnLength当然

就是错的了Julykupdated

41

42charpFirstStartpStr

43charpFirstEndpStrn-1

44charpSecondStartpStrn

45charpSecondEndpStrnLength-1

46

47reversethefirstpartofthestring

48ReverseStringpFirstStartpFirstEnd

49reversethesecondpartofthestrint

50ReverseStringpSecondStartpSecondEnd

51reversethewholestring

52ReverseStringpFirstStartpSecondEnd

53

54

55returnpStr

56

57

58intmain

59

60chara[11]"helloJuly"2修正以一个数组实现存储整个字符串

61charpsa

62LeftRotateStringps6

63forps0ps

64coutps

65coutendl

66psNULL代码规范

67return0

68

11

上述修正的俩处错误如下所示

1如上注释中所述

ifnLength0nnLength

nLength是整个字符串的长度吧n是左边的一部分所以应该是nnLength

2至于之前的主函数为什么编写错误请看下面的注释

intmain

charps"helloJuly"本身没错但你不能对ps所指的字符串做任何修改

这句其实等价于constcharps"helloJuly"

LeftShiftStringps4而在这里试图修改ps所指的字符串常量所以将出现错误

putsps

return0

当然上面的解释也不是完全正确的正如ivan所说从编程实践来说不完全对

如果在一个大的工程里面你怎么知道ps指向的是""字符串还是malloc出来的东西

那么如何决定要不要对ps进行delete

不过至少第26题的思路一的代码最终完整修正完全了

13updated

可能你还是感觉上述代码有点不好理解ok下面再给出一段c实现的代码

然后我们可以看到c的高效与简洁

1copyrightyiyibuptJuly

2已测试正确Julyupdatedcom

3不要小看每一段程序July

4include

5include

6

7voidrotatecharstartcharend

8

9whilestartNULLendNULLstartend

10

11chartempstart

12startend

13endtemp

14start

15end--

12

16

17

18

19

20voidleftrotatecharpintm

21

22ifpNULL

23return

24intlenstrlenp

25ifm0mlen

26

27charxfirstxend

28charyfirstyend

29xfirstp

30xendpm-1

31yfirstpm

32yendplen-1

33rotatexfirstxend

34rotateyfirstyend

35rotatepplen-1

36

37

38

39intmainvoid

40

41charstr[]"abcdefghij"

42leftrotatestr3

43printf"sn"str

44return0

45

第二节两指针逐步翻转

先看下网友litaoye的回复26左旋转字符串跟panda所想是一样的即

以abcdef为例

1ab-ba

2cdef-fedc

原字符串变为bafedc

3整个翻转cdefab

只要俩次翻转且时间复杂度也为On

13

21在此本人再奉献另外一种思路即为本思路二

abcdefghi要abc移动至最后

abcdefghi-defabcghi-defghiabc

定义俩指针p1指向ch[0]p2指向ch[m]

一下过程循环m次交换p1和p2所指元素然后p1p2

第一步交换abc和def

abcdefghi-defabcghi

第二步交换abc和ghi

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 法律文书 > 判决书

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1