程序员面试题精选100题(34-59)

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

程序员面试题精选100题(34)-找出数组中两个只出现一次的数字数组2007-12-2821:50:06阅读6227评论10字号:大中小订阅题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。分析:这是一道很新颖的关于位运算的面试题。首先我们考虑这个问题的一个简单版本:一个数组里除了一个数字之外,其他的数字都出现了两次。请写程序找出这个只出现一次的数字。这个题目的突破口在哪里?题目为什么要强调有一个数字出现一次,其他的出现两次?我们想到了异或运算的性质:任何一个数字异或它自己都等于0。也就是说,如果我们从头到尾依次异或数组中的每一个数字,那么最终的结果刚好是那个只出现依次的数字,因为那些出现两次的数字全部在异或中抵消掉了。有了上面简单问题的解决方案之后,我们回到原始的问题。如果能够把原数组分为两个子数组。在每个子数组中,包含一个只出现一次的数字,而其他数字都出现两次。如果能够这样拆分原数组,按照前面的办法就是分别求出这两个只出现一次的数字了。我们还是从头到尾依次异或数组中的每一个数字,那么最终得到的结果就是两个只出现一次的数字的异或结果。因为其他数字都出现了两次,在异或中全部抵消掉了。由于这两个数字肯定不一样,那么这个异或结果肯定不为0,也就是说在这个结果数字的二进制表示中至少就有一位为1。我们在结果数字中找到第一个为1的位的位置,记为第N位。现在我们以第N位是不是1为标准把原数组中的数字分成两个子数组,第一个子数组中每个数字的第N位都为1,而第二个子数组的每个数字的第N位都为0。现在我们已经把原数组分成了两个子数组,每个子数组都包含一个只出现一次的数字,而其他数字都出现了两次。因此到此为止,所有的问题我们都已经解决。基于上述思路,我们不难写出如下代码://///////////////////////////////////////////////////////////////////////Findtwonumberswhichonlyappearonceinanarray//Input:data-anarraycontainstwonumberappearingexactlyonce,//whileothersappearingexactlytwice//length-thelengthofdata//Output:num1-thefirstnumberappearingonceindata//num2-thesecondnumberappearingonceindata///////////////////////////////////////////////////////////////////////voidFindNumsAppearOnce(intdata[],intlength,int&num1,int&num2){if(length2)return;//getnum1^num2intresultExclusiveOR=0;for(inti=0;ilength;++i)resultExclusiveOR^=data[i];//getindexofthefirstbit,whichis1inresultExclusiveORunsignedintindexOf1=FindFirstBitIs1(resultExclusiveOR);num1=num2=0;for(intj=0;jlength;++j){//dividethenumbersindataintotwogroups,//theindexOf1bitofnumbersinthefirstgroupis1,//whileinthesecondgroupis0if(IsBit1(data[j],indexOf1))num1^=data[j];elsenum2^=data[j];}}/////////////////////////////////////////////////////////////////////////Findtheindexoffirstbitwhichis1innum(assumingnot0)///////////////////////////////////////////////////////////////////////unsignedintFindFirstBitIs1(intnum){intindexBit=0;while(((num&1)==0)&&(indexBit32)){num=num1;++indexBit;}returnindexBit;}/////////////////////////////////////////////////////////////////////////IstheindexBitbitofnum1?///////////////////////////////////////////////////////////////////////boolIsBit1(intnum,unsignedintindexBit){num=numindexBit;return(num&1);}博主何海涛对本博客文章享有版权。网络转载请注明出处。整理出版物请和作者联系。程序员面试题精选100题(35)-找出两个链表的第一个公共结点链表2008-01-0515:16:09阅读6477评论13字号:大中小订阅题目:两个单向链表,找出它们的第一个公共结点。链表的结点定义为:structListNode{intm_nKey;ListNode*m_pNext;};分析:这是一道微软的面试题。微软非常喜欢与链表相关的题目,因此在微软的面试题中,链表出现的概率相当高。如果两个单向链表有公共的结点,也就是说两个链表从某一结点开始,它们的m_pNext都指向同一个结点。但由于是单向链表的结点,每个结点只有一个m_pNext,因此从第一个公共结点开始,之后它们所有结点都是重合的,不可能再出现分叉。所以,两个有公共结点而部分重合的链表,拓扑形状看起来像一个Y,而不可能像X。看到这个题目,第一反应就是蛮力法:在第一链表上顺序遍历每个结点。每遍历一个结点的时候,在第二个链表上顺序遍历每个结点。如果此时两个链表上的结点是一样的,说明此时两个链表重合,于是找到了它们的公共结点。如果第一个链表的长度为m,第二个链表的长度为n,显然,该方法的时间复杂度为O(mn)。接下来我们试着去寻找一个线性时间复杂度的算法。我们先把问题简化:如何判断两个单向链表有没有公共结点?前面已经提到,如果两个链表有一个公共结点,那么该公共结点之后的所有结点都是重合的。那么,它们的最后一个结点必然是重合的。因此,我们判断两个链表是不是有重合的部分,只要分别遍历两个链表到最后一个结点。如果两个尾结点是一样的,说明它们用重合;否则两个链表没有公共的结点。在上面的思路中,顺序遍历两个链表到尾结点的时候,我们不能保证在两个链表上同时到达尾结点。这是因为两个链表不一定长度一样。但如果假设一个链表比另一个长l个结点,我们先在长的链表上遍历l个结点,之后再同步遍历,这个时候我们就能保证同时到达最后一个结点了。由于两个链表从第一个公共结点考试到链表的尾结点,这一部分是重合的。因此,它们肯定也是同时到达第一公共结点的。于是在遍历中,第一个相同的结点就是第一个公共的结点。在这个思路中,我们先要分别遍历两个链表得到它们的长度,并求出两个长度之差。在长的链表上先遍历若干次之后,再同步遍历两个链表,知道找到相同的结点,或者一直到链表结束。此时,如果第一个链表的长度为m,第二个链表的长度为n,该方法的时间复杂度为O(m+n)。基于这个思路,我们不难写出如下的代码://///////////////////////////////////////////////////////////////////////FindthefirstcommonnodeinthelistwithheadpHead1and//thelistwithheadpHead2//Input:pHead1-theheadofthefirstlist//pHead2-theheadofthesecondlist//Return:thefirstcommonnodeintwolist.Ifthereisnocommon//nodes,returnNULL///////////////////////////////////////////////////////////////////////ListNode*FindFirstCommonNode(ListNode*pHead1,ListNode*pHead2){//GetthelengthoftwolistsunsignedintnLength1=ListLength(pHead1);unsignedintnLength2=ListLength(pHead2);intnLengthDif=nLength1-nLength2;//GetthelongerlistListNode*pListHeadLong=pHead1;ListNode*pListHeadShort=pHead2;if(nLength2nLength1){pListHeadLong=pHead2;pListHeadShort=pHead1;nLengthDif=nLength2-nLength1;}//Moveonthelongerlistfor(inti=0;inLengthDif;++i)pListHeadLong=pListHeadLong-m_pNext;//Moveonbothlistswhile((pListHeadLong!=NULL)&&(pListHeadShort!=NULL)&&(pListHeadLong!=pListHeadShort)){pListHeadLong=pListHeadLong-m_pNext;pListHeadShort=pListHeadShort-m_pNext;}//GetthefirstcommonnodeintwolistsListNode*pFisrtCommonNode=NULL;if(pListHeadLong==pListHeadShort)pFisrtCommonNode=pListHeadLong;returnpFisrtCommonNode;}/////////////////////////////////////////////////////////////////////////GetthelengthoflistwithheadpHead//Input:pHead-theheadoflist//Return:thelengthoflist///////////////////////////////////////////////////////////////////////unsignedintListLength(ListNode*pHead){unsignedintnLength=0;ListNode*pNode=pHead;while(pNode!=NULL){++nLength;pNode=pNode-m_pNext;}returnnLength;}博主何海涛对本博客文章享有版权。网络转载请注明出处。整理出版物请和作者联系。程序员面试题精选100题(36)-在字符串中删除特定的字符字符串2008-01-1915:14:26阅读7133评论15字号:大中小订阅题目:输入两个字符串,从第一字符串中删除第二个字符串中所有的字符。例如,输入”Theyares

1 / 78
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功