C++ 面试必备100题 经典问题带答案分析 程序员面试必备if(pRightpRight pRightpRight->m pLeft pNodeBSTreeNode *pTemp= pNode;// If the current node is the right child of its parenti// return the least node in the tree whose root is the current nodef(arIght)while(ptemp->m pLett)pTemp pTemp->m pLefti//If the current node is the left chila of its parent// return the greatest node in the tree whose root is the current nodeelsehile(p'temp->m pRight)TempoTemp->m pRightreturn pfermp;/ Covert a binary search tree into a sorted double-linked list// Input: the head of tree/ Output: the head of sorted double-linked listBSTreeNode* Convert(BSTreeNode* pHeadofTree)// As we want. o return the head of the sorted do ole-linked list// we set the second parameter to be truereturn ConvertNode(pHeadofrree, true)i思路二对应的代码:/ Covert a sub birary-search-tree into a sorted double-linked list//工nputthe head of the sub treepLastNodeInList the tail of the double-linked listvoid ConvertNode(BsTreeNodek pNode, BSTreeNode*& pLastNcceInListif(pNode = NULL)returniBSTreeNode pCurrent pNcde// Convert the left sub-treeif (pCurrent->m pLeft!= NULLonvertNode(pCurrent->m plett, plastNodeinlist)i// Put the current node into the double-linked listCurrent->m pLeft pLastNodeInListif(plastNodeirlist NULL)pLastNodeinlist->m pRight pCurrentipLastNodeinList pCurrentiConvert the right sub-treeif (pCurrent->m pRight ! NULL)ConvertNode(pCurrent->Ill pRight, pLastNodeInlist)i/ Covert a binary search tree into a sorted double-linked list/ Input: pHeadofTree the head of tree/ Output: the head of sorted double-linked Iist.ESTreeNode* Convert Solutionl(BsTreeNode* pHeadoffree)BSTreeNode * plastNodeinlist =NUlliConvertNode(pheadofTree, PLastNodeInLis-)/ Get the head of the double-linked listBSTreeNode *pFeadoflist pLastNodeInlistiwhile(pheadoflist & pHeadoflist->m pLeft)oHeado-=List pHeadofList->Ill PLeftreturn pHeadoflist(02)设计包含mn函数的栈题目:定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。要求函数minpush以及pop的时间复杂度都是O(1)。分析:这是去年 google的一道面试题。我看到这道题目时,第一反应就是每次push一个新元素时,将栈里所有逆序元素排序。这样栈顶元素将是最小元素。但由于不能保证最后push进栈的元素最先出栈,这种思路设计的数据结构己经个是一个栈了。在栈里添加一个成员变量存放最小元素(或最小元素的位置)。每次push一个新元素进栈的时候,如果该元素比当前的最小元素还要小,则更新最小元素。乍一看这样思路挺好的。但仔细一想,该思路存在一个重要的问题:如果当前最小元素被pop出去,如何才能得到下一个最小元素?因此仅仅只添加一个成员变量存放最小元素(或最小元素的位置)是个够的。我们需要一个辅助栈。每次push一个新元素的时候,同时将最小元素(或最小元素的位置。考虑到栈元素的类型可能是复杂的数据结构,用最小元素的位置将能减少空间消耗)push到辅助栈中;每次pop一个元素出栈的时候,同时pop辅助栈。参考代码:include include template class cstackWithMinpublic:CStackwithMin(void)iirtua l -CstackwithMin(void)tjT& top (void)iconst T& top(void)constivoid push(ccnst T& value));const T& min(void)constipr⊥vate:T>m datai// theelements cf stackize t>m minIndexi// the indicesof minimum elements};/ get the last element of mutable stacktemplate < typename T> T& CStackWithMin:: top(return m data back(/ get the last element of ncn-mutable stacktemplate const T& CStackWithNin:: top()constreturn m data back(i// insert an elment at the end of stacktemplate void CStackilithMin:: push(const T& value)// append the data into the end of m dacam data push back(value)// set the index of minimum e l ment in m data at the end of m mintndexif(n ninIndex size(== 0)m minIndex. push back(0)ilseif(value m datalm minTndex back()j)ct minIr dex. push back(in data size(elsem minIrdex. push back(m minIndex back())// erease the element at the erd of stacktemplate void CstackNithMin:: pop(// pop m datam data. pop back()imindexIml IninIndex pop back(i// get the minimum element of stacktemplate const T& CStackWithMin:: min()corstassert(m data size(>0);assert(m minIrdex size()>0)ireturn m data lm minIndex back(]i举个例子演示上述代码的运行过程步骤数据栈辅助栈最小值1. push 332. push 43. push 20,0,24. push 13,4,2,10,0,2,30,0,26.p○p0,0212307. push 00,0,2讨论:如果思路正确,编写上述代码不是一件很难的事情。但如果能注意一些细节无疑能在面试中加分。比如我在上面的代码中做了如下的工作用模板类实现。如果别人的元素类型只是int类型,模板将能给面试官带来好印象:;两个版本的top函数。在很多类中,都需要提供 const和非 const版本的成员访问函数min函数中 assert。把代码写的尽量安全是每个软件公司对程序员的要求;添加一些注释。注释既能提高代码的可读性,又能増加代码量,何乐而不为?总之,在面试时如果时间允许,尽量把代码写的漂亮一些。说不定代码中的几个小亮点就能让自凵轻松拿到心仪的Ofer(03)求子数组的最大和题目:输入一个整形数组,数组里有正数也有负数。数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。求所有子数组的和的最人值。要求时间复杂度为O(n)例如输入的数组为1,-2,3,10,4,7,2,-5,和最大的了数组为3,10,-4,7,2,因此输出为该」数组的和18。分析:本题最初为2005年浙江大学计算机系的考研题的最后一道程序设计题,在2006年里包括 google在内的很多知名公司都把木题当作面试题。由于木题在网络中广为流传,木题也顺利成为2006年程序员面试题中经典中的经典。如果不考虑时间复杂度,我们可以枚举出所有子数组并求出他们的和。不过非常遗憾的是,由于长度为n的数组有O(m2)个子数组;而且求一个长度为n的数组的和的时间复杂度为O(n)因此这种思路的时间是O(n很容易理解,当我们加上个止数时,和会增加;当我们加上个负数时,和会减少。如果当前得到的和是个负数,那么这个和在接下来的累加中应该抛弃并重新清零,不然的话这个负数将会减少接下米的和。基于这样的思路,我们可以写出如下代码。参考代码://////// Find the greatest sun of all sub-arrays/ Return value: if the input is valid, return true, otherwise return false////////bocl FindGreatest SubArrayint *pDat.a7, an arrayunsigned int lEngth, / the length of arrayint &ngreatestsum// the greatest sum of all sub-arrays// if the input is invalid, return falseif((pData = NULL)I (nLength ==0))return false;irt ncCursum nGreatestsumfor(unsigned int i =0; 1< nLength; ++inCurSum + pData[ii// if the current sunl is negative, discard itif(nCurSum< 0nCurSum =0// it a greater sum is found, update the greatest sumif(nCur SuI nGreatestsuinngreatestsum nCursumi// if all data are negative, find the greatest element in the arrayf(nGreatestsull ==0)nGreatestSum pDatalo;for(unsigned int i =1; i nLength; ++i)if (pData[i]> nGreatestsumncreatestsum= pDatali]ireturn true}讨论:上述代码中有两点值得和大家讨论下函数的返回值不是子数组和的最大值,而是一个判断输入是否有效的标志。如果函数返回值的是子数组和的最大值,那么当输入一个空指针是应该返回什么呢?返回0?那这个函数的用户怎么区分输入无效和子数组和的最大值刚好是0这两中情况呢?基于这个考虑,本人认为把子数组和的最大值以引用的方式放到参数列表中,同时让函数返回一个函数是否正常执行的标志。输入有一类特姝情况需要特殊处理。当输入数组中所有整数都是负数时,子数组和的最大值就是数组中的最大元素。(04)在二元树中找出和为某一值的所有路径题目:输入一个整数和一棵元树。从树的根结点开始往下访问一直到叶结点所经过的所有结点形成一条路径。打卬出和与输入整数相等的所有嵱径。例如输入整数22和如下二元树1012则打印出两条路径:10,12和10,5,7。二元树结点的数据结构定义为struct BinaryTreeNode / a ncde in the binary treeIml nvalue; / value of nodeBinaryTreeNcde *m pleft; / left child of nodeBinaryTreeNcde *m pRighti / right child of ncde分析:这是百度的道笔试题,考查对树这种基本数据结构以及递归函数的理解当访问到某一结点时,把该结点添加到路径上,并累加当前结点的值。如果当前结点为卟结点并且当前路径的和刚好等于输入的整数,则当前的路径符合要求,我们把它打印出来。如果当前结点不是叶结点,则继续访问它的子结点。当前结点访问结束后,递归函数将自动回到父结点。因此我们在函数退出之前要在路径上删除当前结点并减去当前结点的值,以确保返回父结点吋路径刚好是棖结点到父结点的路径我们不难看出保存路径的教据结构实际上是一个栈结构,因为路径要与递归调用状态一敛,而递归调用本质就是一个压栈和出栈的过程参考代码:/ Find paths whose sum equal to expected sumvoid findPathBinaryTreeNcde* pTreeNode, / a node of binary treeintexpectedsum, / the expected sur.td:: vector&path,/ a pathfrom root to current. nccer:t¤t Suin //the surr: of pathif(!pTreeNode)returnicurrent sum + pTreeNode->m nvalueipath. push back(pTreeNode->m nvalue)// if the ncde is a lea=, and the sun is same as pre-defined,// the path is what we want. print the pathbool isleaf =(!pfreeNode->m pLeft & ! pTreeNode->m pRight)iif(current Sum = expectedSum & isleafstd:: vector::iterator iter =path. begin(for( iter path end()i++ iterstd:: cout<<*iter<m pLeft)FindPath(pfreeNode->m pLeftr expectedsum path, current sumif(pTreeNode->m pRightFindPath(pTreeNode->m pRightr expectedsum, path, current sum)i// when we finish visiting a node and rcturn to its parent node// we should delete this node from the path and// minus the rode's value from the currert sumcurrentsum -= pfreeNode->m nvalue; //!! I think here is no usepathI. pop back()i(05)查找最小的k个元素题目:输入n个整数,输出其中最小的k个。例如输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4分析:这道题最简单的思路莫过于把输入的n个整数排序,这样排在最前面的k个数就是最小的k个数。只是这种思路的时间复杂度为 O(n/ogn)。我们试着寻找更快的解决思路。我们可以开辟一个长度为k的数组。每次从输入的n个整数中读入一个数。如果数组中已经插入的元素少于k个,则将读入的整数直接放到数组中。否则长度为k的数组已经满了,不能再往数组里插入元索,只能替换了。如果读入的这个整数比数组中凵有k个整数的最大值要小,则用读入的这个整数替换这个最大值;如果读入的整数比数组中已有k个整数的最大值还要大,则读入的这个整数不可能是最小的k个整数之,抛弁这个整数。这种思路相当于只要排序k个整数,因此时间复杂可以降到O(n+nogk)。通常情况下k要远小于n所以这种办法要优于前面的思路