1、前二十答案加试题永久勘误:微软等面试100题系列,答案V0.2版第1-20题答案1.把二元查找树转变成排序的双向链表题目:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。要求不能创建任何新的结点,只调整指针的指向。10/ 6 14/ / 4 8 12 16转换成双向链表4=6=8=10=12=14=16。首先我们定义的二元查找树 节点的数据结构如下:struct BSTreeNodeint m_nValue; / value of nodeBSTreeNode *m_pLeft; / left child of nodeBSTreeNode *m_pRight; / right c
2、hild of node;/引用 245 楼 tree_star 的回复#include #include struct BSTreeNodeint m_nValue; / value of nodeBSTreeNode *m_pLeft; / left child of nodeBSTreeNode *m_pRight; / right child of node;typedef BSTreeNode DoubleList;DoubleList * pHead;DoubleList * pListIndex;void convertToDoubleList(BSTreeNode * pCur
3、rent);/ 创建二元查找树void addBSTreeNode(BSTreeNode * & pCurrent, int value)if (NULL = pCurrent)BSTreeNode * pBSTree = new BSTreeNode();pBSTree-m_pLeft = NULL;pBSTree-m_pRight = NULL;pBSTree-m_nValue = value;pCurrent = pBSTree;else if (pCurrent-m_nValue) value)addBSTreeNode(pCurrent-m_pLeft, value);else if
4、 (pCurrent-m_nValue) m_pRight, value);else/cout重复加入节点m_pLeft)ergodicBSTree(pCurrent-m_pLeft); / 节点接到链表尾部convertToDoubleList(pCurrent);/ 右子树为空if (NULL != pCurrent-m_pRight)ergodicBSTree(pCurrent-m_pRight);/ 二叉树转换成listvoid convertToDoubleList(BSTreeNode * pCurrent)pCurrent-m_pLeft = pListIndex;if (NUL
5、L != pListIndex)pListIndex-m_pRight = pCurrent;elsepHead = pCurrent; pListIndex = pCurrent;coutm_nValue NULL (MIN=10, POS=0)1: 7 - 0 (MIN=7, POS=1) 用数组表示堆栈,第0个元素表示栈底2: 3 - 1 (MIN=3, POS=2)3: 3 - 2 (MIN=3, POS=3)4: 8 - NULL (MIN=3, POS=3) 技巧在这里,因为8比当前的MIN大,所以弹出8不会对当前的MIN产生影响5:5 - NULL (MIN=3, POS=3)6
6、: 2 - 2 (MIN=2, POS=6) 如果2出栈了,那么3就是MIN7: 6 - 6出栈的话采用类似方法修正。所以,此题的第1小题,即是借助辅助栈,保存最小值,且随时更新辅助栈中的元素。如先后,push 2 6 4 1 5stack A stack B(辅助栈)4: 5 1 /push 5,min=p-3=1 3: 1 1 /push 1,min=p-3=1 | /此刻push进A的元素1小于B中栈顶元素22: 4 2 /push 4,min=p-0=2 |1: 6 2 /push 6,min=p-0=2 |0: 2 2 /push 2,min=p-0=2 |push第一个元素进A,也
7、把它push进B,当向Apush的元素比B中的元素小, 则也push进B,即更新B。否则,不动B,保存原值。向栈A push元素时,顺序由下至上。辅助栈B中,始终保存着最小的元素。然后,pop栈A中元素,5 1 4 6 2A B -更新 4: 5 1 1 /pop 5,min=p-3=1 |3: 1 1 2 /pop 1,min=p-0=2 |2: 4 2 2 /pop 4,min=p-0=2 |1: 6 2 2 /pop 6,min=p-0=2 |0: 2 2 NULL /pop 2,min=NULL v当pop A中的元素小于B中栈顶元素时,则也要pop B中栈顶元素。3.求子数组的最大和
8、题目:输入一个整形数组,数组里有正数也有负数。数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。求所有子数组的和的最大值。要求时间复杂度为O(n)。例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为3, 10, -4, 7, 2,因此输出为该子数组的和18。/July 2010/10/18#include int maxSum(int* a, int n)int sum=0;int b=0;for(int i=0; in; i+)if(b0)b=ai;elseb+=ai;if(sumb)sum=b;return sum;int main()in
9、t a10=1,-8,6,3,-1,5,7,-2,0,1;coutmaxSum(a,10)endl;return 0;运行结果,如下:20Press any key to continue-int maxSum(int* a, int n)int sum=0;int b=0;for(int i=0; in; i+)if(b=0) /此处修正下,把b0改为 b=0b=ai;elseb+=ai;if(sumb)sum=b;return sum;/解释下:例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5,那么最大的子数组为3, 10, -4, 7, 2,因此输出为该子数组的和18
10、所有的东西都在以下俩行,即:b : 0 1 -1 3 13 9 16 18 7 sum: 0 1 1 3 13 13 16 18 18其实算法很简单,当前面的几个数,加起来后,bsum,则更新sum=b;若bsum,则sum保持原值,不更新。:)。July、10/31。/第4题,当访问到某一结点时,把该结点添加到路径上,并累加当前结点的值。如果当前结点为叶结点并且当前路径的和刚好等于输入的整数,则当前的路径符合要求,我们把它打印出来。如果当前结点不是叶结点,则继续访问它的子结点。当前结点访问结束后,递归函数将自动回到父结点。因此我们在函数退出之前要在路径上删除当前结点并减去当前结点的值,以确保
11、返回父结点时路径刚好是根结点到父结点的路径。我们不难看出保存路径的数据结构实际上是一个栈结构,因为路径要与递归调用状态一致,而递归调用本质就是一个压栈和出栈的过程。void FindPath(BinaryTreeNode* pTreeNode, / a node of binary treeint expectedSum, / the expected sumstd:vector& path, / a path from root to current nodeint& currentSum / the sum of path)if(!pTreeNode)return;currentSum +
12、= pTreeNode-m_nValue;path.push_back(pTreeNode-m_nValue);/ if the node is a leaf, and the sum is same as pre-defined,/ the path is what we want. print the pathbool isLeaf = (!pTreeNode-m_pLeft & !pTreeNode-m_pRight);if(currentSum = expectedSum & isLeaf) std:vector:iterator iter = path.begin();for(; i
13、ter != path.end(); + iter)std:cout *iter t;std:cout m_pLeft)FindPath(pTreeNode-m_pLeft, expectedSum, path, currentSum);if(pTreeNode-m_pRight)FindPath(pTreeNode-m_pRight, expectedSum, path, currentSum);/ when we finish visiting a node and return to its parent node,/ we should delete this node from th
14、e path and/ minus the nodes value from the current sumcurrentSum -= pTreeNode-m_nValue;path.pop_back();5.查找最小的k个元素题目:输入n个整数,输出其中最小的k个。例如输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4。/July 2010/10/18/引用自116 楼 wocaoqwer 的回复。#includeusing namespace std;class MinKpublic:MinK(int *arr,int si):array(arr),size(s
15、i)bool kmin(int k,int*& ret)if(ksize)ret=NULL;return false;elseret=new intk-;int i;for(i=0;i=0;-j)shiftDown(ret,j,k);for(;isize;+i)if(arrayiret0)ret0=arrayi;shiftDown(ret,0,k);return true;void remove(int*& ret)delete ret;ret=NULL;private:void shiftDown(int *ret,int pos,int length)int t=retpos;for(in
16、t s=2*pos+1;s=length;s=2*s+1)if(slength&retsrets+1)+s;if(trets)retpos=rets;pos=s;else break;retpos=t;int *array;int size;int main()int array=1,2,3,4,5,6,7,8;MinK mink(array,sizeof(array)/sizeof(array0);int *ret;int k=4;if(mink.kmin(k,ret)for(int i=0;ik;+i)coutretiendl;mink.remove(ret);return 0;/运行结果
17、:4231Press any key to continue/-第5题,也可以:用类似快排的partition的方法,只求2边中的一边,在O(N)时间得到第k大的元素v; 再扫描一遍( O(N) ),得到所有小于等于v的元素。其中,快速排序每一趟比较用时O(n),要进行lgn次比较,才最终完成整个排序。所以快排的复杂度才为O(n*lgn)。像现在,只需要,找到第k大的元素,排一趟是O(n),排俩趟是O(2n),其中第二趟,可以在第一趟后选择排序哪边,即只要排一边了,递归找到第k大的元素,是O(N)的复杂度,最后遍历那一边O(k),输出这k个元素,即可。所以,总的运行时间复杂度为O(N)。(如果
18、,要有序输出的话,则再将那k的元素排序,时间复杂度为O(N+klgk)。)-第5题,再具体阐述下:类似快排中的分割算法(如果不清楚快速排序,请参考本BLOG内关于快速排序的倆篇文章):每次分割后都能返回枢纽点在数组中的位置s,然后比较s与k的大小若大的话,则再次递归划分arrays.n,小的话,就递归arrayleft.s-1 /s为中间枢纽点元素。否则返回arrays,就是partition中返回的值。 /就是要找到这个s。找到符合要求的s值后,再遍历输出比s小的那一边的元素。代码实现:/引自飞羽。int kth_elem(int a,int low, int high,int k)int
19、pivot=alow;int low_temp = low;int high_temp = high;while(lowhigh)while(lowpivot) -high;alow=ahigh;while(lowhigh&alowk-1) return kth_elem(a,low_temp,low-1,k);else return kth_elem(a,low+1,high_temp,k);-后序补充:关于分治思想:如果第一次 分划,找到的第s小符合要求m,则停止,如果找到的第s小,sm,则 到s的左边继续找。举例说明:2 1 3 6 4 5假设第一次划分之后,3为中间元素:1、如果要求找
20、第3小的元素,而找到的s=m(要求),则返回32、如果要求找第1小的元素,而找到的sm,则在s的左边找3、如果要求找第4小的元素,而找到的sm,则在s的右边找。在算法导论上,第九章中,以期望线性时间做选择,一节中,我找到了这个 寻找数组中第k小的元素的,平均时间复杂度为O(N)的证明。中文版是 第110页,英文版约是第164页。不是一趟O(N),而是最终找到那第k个数,然后将其输出,的复杂度为O(N)。(或者,O(n+k),最后遍历那k个元素输出。)。利用的正是上述类似快排中的分治算法,而与快速排序不同的是:即快速排序要递归处理划分后的俩边,而此上述程序,即本题需处理划分之后的一边。所以,快速
21、排序的期望运行时间为O(nlgn),而上述程序的期望运行时间,最后证明可得O(n),且假定元素是不同的。第6题-腾讯面试题: 给你10分钟时间,根据上排给出十个数,在其下排填出对应的十个数 要求下排每个数都是先前上排那十个数在下排出现的次数。 上排的十个数如下: 【0,1,2,3,4,5,6,7,8,9】初看此题,貌似很难,10分钟过去了,可能有的人,题目都还没看懂。 举一个例子, 数值: 0,1,2,3,4,5,6,7,8,9 分配: 6,2,1,0,0,0,1,0,0,0 0在下排出现了6次,1在下排出现了2次, 2在下排出现了1次,3在下排出现了0次. 以此类推. / 引用自July 2
22、010年10月18日。/数值: 0,1,2,3,4,5,6,7,8,9/分配: 6,2,1,0,0,0,1,0,0,0#include #define len 10class NumberTB private:int toplen; int bottomlen;bool success;public:NumberTB();int* getBottom();void setNextBottom();int getFrequecy(int num);NumberTB:NumberTB() success = false; /format top for(int i=0;ilen;i+) topi
23、= i; int* NumberTB:getBottom() int i = 0; while(!success) i+; setNextBottom(); return bottom; /set next bottom void NumberTB:setNextBottom() bool reB = true; for(int i=0;ilen;i+) int frequecy = getFrequecy(i); if(bottomi != frequecy) bottomi = frequecy; reB = false; success = reB; /get frequency in bottom int NumberTB:getFrequecy(int num) /此处的num即指上排的数 i int count = 0; for(int i=0;ilen;i+) if(bottomi = num) count+; return count; /cout即对应 frequecyint main() NumberTB nTB;int* result= nTB.getBottom(); for(int i=0;ilen;i+) cout*result+endl;
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1