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

 作者:July、编程艺术室。
出处: http://blog.csdn.net/v_JULY_v 
题记   

    好久没更新博客了,虽只有一个月,但对我来说,已是长久。最重要的是11月初来北京后,在这近一个月找工作的过程中,面试、拜访、购书、读书,亦许久没有敲代码了,手异常生疏,虽只有一个月,但对我来说,仍已是长久。为了表示我一直在关注着本博客,从未曾离开,也为了可以更多的思考,更为了让手不致生疏,更新吧。

    ok,针对微软100题一题一题解答的,程序员编程艺术已经写到第二十二章了(艺术这个高帽子早已有意摘取之,然都戴了这么久了,还是戴着好了),其中有些题目的解答甚是值得商榷,再者,把这些文章和题目的大致摘要、详情列出来,也方便读者阅读,回顾,适应读者所需亦能方便你我更好的思考。

    前十章的总结见这:程序员编程艺术第一~十章集锦与总结。下面,把已经写过的编程艺术的前二十二章总结下,这几十道题目的解答若是有任何漏洞、疏漏以致错误,读者如经发觉之,还望不吝赐教或予以批评指正,本人感激不尽,谢谢。

无私分享,造福天下

程序员编程艺术第一~二十二章,下面,是各章的大致摘要,详情还请打开链接参看原文:

    原题为:定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部。
如把字符串abcdef左旋转2位得到字符串cdefab。
请实现字符串左旋转的函数,要求对长度为n的字符串操作的时间复杂度为O(n),空间复杂度为O(1)。

    原文中,给出了以下几种思路:

  1. 拿abcdef 这个例子来说:
    1、首先分为俩部分,X:abc,Y:def;
    2、X->X^T,abc->cba, Y->Y^T,def->fed。
    3、(X^TY^T)^T=YX,cbafed->defabc,即整个翻转。
  2. 两指针一前一后,逐步翻转;
  3. 通过递归转换,缩小问题之规模;
  4. stl::rotate 算法;

     在经过这道左旋转字符串题目的搜索,发现,搜索引擎的第一个选项竟大部是链接自转载本文文章的其它网站,不指原创、原版,反指转载、盗版,所以,接下来,不再给出搜索结果的示意图了。

 

    原题为:假设这有一个各种字母组成的字符串,假设这还有另外一个字符串,而且这个字符串里的字母数相对少一些。从算法是讲,什么方法能最快的查出所有小字符串里的字母在大字符串里都有?

比如,如果是下面两个字符串:
String 1: ABCDEFGHLMNOPQRS
String 2: DCGSRQPOM
答案是true,所有在string2里的字母string1也都有。
 
如果是下面两个字符串:  
String 1: ABCDEFGHLMNOPQRS  
String 2: DCGSRQPOZ  
答案是false,因为第二个字符串里的Z字母不在第一个字符串里。

 

    原题为:5.查找最小的k个元素
题目:输入n个整数,输出其中最小的k个。
例如输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4。

 

    原题为:搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。
    假设目前有一千万个记录(这些查询串的重复度比较高,虽然总数是1千万,但如果除去重复后,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就是越热门。),请你统计最热门的10个查询串,要求使用的内存不能超过1G。

 

     “ok,狂想曲第三章提出了一个算法,就是快速选择SELECT算法,关于这个SELECT算法通过选取数组中中位数的中位数作为枢纽元能保证在最坏情况下,亦能做到线性O(N)的时间复杂度的证明,在狂想曲第三章也已经给出。”

 

伴随数组

原第一次排序后:

      a [i].data  1 2 3 4 5 6 7
      a [i].num  1 3 5 7 2 4 6

再次扫描,直接O(N)搞定:

      a [i].data   1 2 3 4 5 6 7
      a [i].num   1 3 5 7 2 4 6
         k           3 2 1 1 1 0

(而之前有的读者意识不到伴随数组的意义,是因为一般的人只考虑找一次,不会想到第二次或多次查找)

 

“很多中、小型公司自己的创造能力,包括人力,物力资源都有限,所以,他们的面试题目除了copy一些大公司的题库之外(当然,考察你对基础知识的掌握情况,是肯定不会放过的),还有一个途径就是让你在限定时间内(如十分钟),当场实现一些类似strcpy/strcat/strpbrk等库函数,这个主要看你对细节的把握,以及编程能力是否之扎实了。”

 

    原题为:

  1. 输入一个数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。
    要求时间复杂度是O(n)。如果有多对数字的和等于输入的数字,输出任意一对即可。
    例如输入数组1、2、4、7、11、15和数字15。由于4+11=15,因此输出4和11。
  2. 输入两个整数 n 和 m,从数列1,2,3.......n 中 随意取几个数,
    使其和等于 m ,要求将其中所有的可能组合列出来。

 

    原题为:求500万以内的所有亲和数
如果两个数a和b,a的所有真因数之和等于b,b的所有真因数之和等于a,则称a,b是一对亲和数。
例如220和284,1184和1210,2620和2924。

 

    原题为:输入一个整形数组,数组里有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
求所有子数组的和的最大值。要求时间复杂度为O(n)。

    例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为3, 10, -4, 7, 2,因此输出为该子数组的和18。

 

  

 

    原题为:输入:一个最多含有n个不重复的正整数(也就是说可能含有少于n个不重复正整数)的文件,其中每个数都小于等于n,且n=10^7。
输出:得到按从小到大升序排列的包含所有输入的整数的列表。
条件:最多有大约1MB的内存空间可用,但磁盘空间足够。且要求运行时间在5分钟以下,10秒为最佳结果。

 

    “什么是最长公共子序列呢?好比一个数列 S,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则S 称为已知序列的最长公共子序列。 举个例子,如:有两条随机序列,如 1 3 4 5 5 ,and 2 4 5 5 7 6,则它们的最长公共子序列便是:4 5 5。”

 

    本文分为以下4部分:

  1. 第一部分、从一道题,漫谈数据结构、以及压缩、位图算法,由上善若水.qinyu完成,
  2. 第二部分、遍历n个元素取出等概率随机取出其中之一元素,由BigPotato完成,
  3. 第三部分、提取出某日访问百度次数最多的那个IP,由luuillu完成,
  4. 第四部分、回文判断,由well完成。全文由July统稿完成。

 

本章讲解了以下几道题:

    • 全排列;
    • 跳台阶;
    • 奇偶排序;
    • 第一个只出现一次的字符;
    • 一致性哈希算法。

 

    此文阐述了两个问题:

  1. 数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。
  2. 你我在百度或谷歌搜索框中敲入本博客名称的前4个字“结构之法”,便能在第一个选项看到本博客的链接,如下图2所示:
 
                                      图2  谷歌中搜索关键字“结构之法”

  在上面所示的图2中,搜索结果“结构之法算法之道-博客频道-CSDN.NET”下有一段说明性的文字:“ 程序员面试、算法研究、编程艺术、红黑树4大经典原创系列集锦与总结 作者:July-- 结构之法 算法...”,我们把这段文字称为那个搜索结果的摘要,亦即最短摘要。我们的问题是,请问,这个最短摘要是怎么生成的呢?

第一~二十二章,完。

下期预告    

    下面,练练代码,同时,可能会作为编程艺术系列后续章节的内容:

    1、合并两个排序的链表。即输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的。

//合并两个排序的链表
//copyright@2011 剑指offer
ListNode* Merge(ListNode* pHead1,ListNode* pHead2)
{
  if(pHead1 == NULL)
    return pHead2;
  else if(pHead == NULL)
    return pHead1;

  ListNode* pMergedHead = NULL;

  if(pHead1->m_nValue < pHead->m_nValue)
  {
    pMergedHead=pHead1;
    pMergedHead->m_pNext=Merge(pHead1->m_pNext,pHead2);
  }
  else
  {
    pMergedHead=pHead2;
    pMergedHead->m_pNext=Merge(pHead1,pHead2->m_pNext);
}

   return pMergedHead;
}

//非递归实现 链表合并排序
//copyright@ 2011 July
Node * Merge(Node *head1 , Node *head2)
{
    if ( head1 == NULL)
        return head2 ;
    if ( head2 == NULL)
        return head1 ;
    Node *head = NULL ;
    Node *p1 = NULL;
    Node *p2 = NULL;

    if ( head1->data < head2->data )
    {
        head = head1 ;
        p1 = head1->next;
        p2 = head2 ;
    }
    else
    {
        head = head2 ;
        p2 = head2->next ;
        p1 = head1 ;
    }

    Node *pcurrent = head ;
    while ( p1 != NULL && p2 != NULL)
    {
        if ( p1->data <= p2->data )
        {
            pcurrent->next = p1 ;
            pcurrent = p1 ;
            p1 = p1->next ;
        }
        else
        {
            pcurrent->next = p2 ;
            pcurrent = p2 ;
            p2 = p2->next ;
        }
    }

    if ( p1 != NULL )
        pcurrent->next = p1 ;
    if ( p2 != NULL )
        pcurrent->next = p2 ;

    return head ;
}
//好久没敲代码了,敲代码的感觉真舒服啊...



 

    2、反转链表

//第24题:反转链表
//pPrev<-pNode<-pNext
//copyright@ 何海涛Harry
ListNode* ReverseIteratively(ListNode* pHead)
{
  ListNode* pReversedHead = NULL;
  ListNode* pNode = pHead;
  ListNode* pPrev = NULL;
  while(pNode != NULL)         //pNode<=>m
  {
    ListNode* pNext = pNode->m_pNext;       //n保存在pNext下

    //如果pNext指为空,则当前结点pNode设为头。
    if(pNext == NULL)
      pReversedHead = pNode;

    // reverse the linkage between nodes
    pNode->m_pNext = pPrev;

    // move forward on the the list
    pPrev = pNode;
    pNode = pNext;
  }
  return pReversedHead;
}

//或者,这样写:
//head->next -> p-> q
template<class T>
Node<T>* Reverse(Node<T>* head)
{
  p=head->next;

  while(p)
  {
    q=p->next;           //p->next先保存在q下
    p->next=head->next;  //p掉头指向head->next
    head->next=p;        //p赋给head->next
    p=q;                 //q赋给p。
    //上俩行即,指针前移嘛...
  }

  return head;
}



 

    编程艺术系列一如之前早已说过,“编程艺术系列最后可能要写到第六十章”(语出:程序员编程艺术第一~十章集锦与总结--面试、算法、编程)。所以,待续....

  如果你暂时无法很好的看懂或理解上文中某道题目或其解答,那只是因为你思考与接收问题的角度与我不同。不过,不用担心,你可以用你自己的方法看懂或理解,只不过这需要一些时间而已。好运!

 

后记

    来北京之前,我曾制作了本博客博文集锦第五期CHM文件,但到此文件的下载地址:http://download.csdn.net/detail/v_july_v/3738298,一看评论,发现很多朋友反应:下下来以后,只显示目录,不显示内容,不能看。

    其实,解决办法很简单,把打开文件之时出现提示框中的“打开文件前总是询问(W)”的勾选去掉即可。为此,下面演示一遍。

    1、从下载地址处下载好后,点击文件,把下面提示框中的“打开文件前总是询问(W)”的勾选去掉

    2、之后直接打开,便可以了,如下图所示:

    3、据读者反馈:如果是vista或者其他系统,则可以右键,属性,修改(一开始目录显示若有问题的话,那么在打开前,属性里面有个“unlock”,点一下就可以成功打开了)。

    So,读者自己不妨亲自再试一次?此文件的下载地址:http://download.csdn.net/detail/v_july_v/3738298。谢谢,希望此文件对你的面试、编程亦或算法学习有所帮助。其它资源下载地址如下:

    同时,朋友正在帮忙把我博客内所有文章整理成带目录+标签的PDF文档,到时候整理出来后,自会分享于大家。

 

    常有朋友问我,算法怎么学。说实话,以前在学校写博客,学算法只是毕业前夕没什么课,刚好空闲干的事情。一个人在没事做,无聊的时候总得找点什么事做,好比多数人选择玩游戏,玩牌也是一种消遣一样,无关追求,无关目的。如果您还不甚满意,可以再看看此文:由快速排序引申而来--如何学习算法。学算法,独有兴趣与激情足矣(当然,一定的语言和数据结构基础也是必不可少的);学编程,你我多敲代码吧。

    也有不少朋友要我推荐一些有关编程或算法学习的基础书籍、资料,在此,推荐如下十项,对的,仅十项:1、c++ primer;2、算法导论;3、c和指针;4、STL源码剖析;5、深度探索c++对象模型;6、编程珠玑;7、编程之美;8、深入理解计算机系统;9、程序员编程艺术(日后可能亦会改名);10、结构之法算法之道blog。

    至于工作,偶正在找一个合适的开发平台与一个合适的职位,努力。而从今往后,本博客内日后的更新可能与现在已有的内容会慢慢千差万别了。详情,读者与我共同期待吧。

 

 

    ok,闲话勿多。如果哪位读者能只看本文给出的原题,而立马反应出各个题目的思路、解决之道,那么,面试无忧矣。且请一定与我联系,定与君多多讨论、交流、请教之。当然,若其他读者发现了此一系列任何一篇文章中任何一题的漏洞、疏漏,亦或错误,也烦请不吝赐教,或者批评指正。你可以通过以下途径与我取得联系:

  1. 本博客算法交流群第16群:Algorithms_16群,30382647(11月内有效);
  2. 我的微博(博客左侧边栏):@v_JULY_v, http://weibo.com/julyweibo,我的邮箱, zhoulei0907@yahoo.cn
  3. TAOPP修订wiki, http://tctop.wikispaces.com/ ;
  4. 目前,个人正在与一位朋友建一论坛,以作群友们交流之地,我想到时候,不论是灌水的,还是搞技术的,都能找到属于自己的乐园。

    始终怀着以一颗谦卑的心,与大家共同学习、交流,以诸君为傲。完。July、二零一一年十一月二十三日。

转自:http://blog.csdn.net/v_july_v/article/details/7004661

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值