微软面试100题及答案2.0版本

从百度文库下载的下载需要积分,贴在这大家随便看就好,不要追究我盗版,哈哈。。。



精选微软等数据结构+算法面试100题
--答案修正V0.2版本
此份答案是针对,前期已公布的最初的那份答案的,初步校正与修正。
http://download.csdn.net/source/2796735(V0.1版)
相比第一份V0.1版答案,此份答案V0.2版更加准确,亦修正了不少题目的答案。
此份20题的答案,思路更加清晰易懂,简介明了。
帖子更新地址:
http://topic.csdn.net/u/20101023/20/5652ccd7-d510-4c10-9671-307a56006e6d.html
若对已公布的面试题有任何问题,请把意见发表在上述帖子上,探讨交流。
所有源码及答案,只做了初步校正,欢迎批评指正。
MyBlog:
http://blog.csdn.net/v_JULY_v
MySinaBlog:
http://blog.sina.com.cn/shitou009
MyE-mail:
zhoulei0907@yahoo.cn
//东华理工、July整理编辑。2010/11/06。
谢谢。
-------我很享受思考的过程,个人思考的全部结果,都放在了这篇帖子上,
http://topic.csdn.net/u/20101023/20/5652ccd7-d510-4c10-9671-307a56006e6d.html
现在,我要,好好整理下,上篇帖子上,已公布出来的题目答案了。
展示自己的思考结果,我觉得很骄傲。:)。
----------------------------------------------------------
2
2010年10月18日下午July
--------------------------------1.把二元查找树转变成排序的双向链表
题目:
输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。
要求不能创建任何新的结点,只调整指针的指向。
10
/\
6 14
/\/\
4 81216
转换成双向链表
4=6=8=10=12=14=16。
首先我们定义的二元查找树节点的数据结构如下:
structBSTreeNode
{
intm_nValue;//valueofnode
BSTreeNode*m_pLeft;//leftchildofnode
BSTreeNode*m_pRight;//rightchildofnode
};
//引用245楼tree_star的回复
#include<stdio.h>
#include<iostream.h>
structBSTreeNode
{
intm_nValue;//valueofnode
BSTreeNode*m_pLeft;//leftchildofnode
BSTreeNode*m_pRight;//rightchildofnode
};
typedefBSTreeNodeDoubleList;
DoubleList*pHead;
DoubleList*pListIndex;
voidconvertToDoubleList(BSTreeNode*pCurrent);
//创建二元查找树
voidaddBSTreeNode(BSTreeNode*&pCurrent,intvalue)
{
if(NULL==pCurrent)
{
BSTreeNode*pBSTree=newBSTreeNode();
3
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);
}
elseif((pCurrent->m_nValue)<value)
{
addBSTreeNode(pCurrent->m_pRight,value);
}
else
{
//cout<<"重复加入节点"<<endl;
}
}
}
//遍历二元查找树中序
voidergodicBSTree(BSTreeNode*pCurrent)
{
if(NULL==pCurrent)
{
return;
}
if(NULL!=pCurrent->m_pLeft)
{
ergodicBSTree(pCurrent->m_pLeft);
}
//节点接到链表尾部
convertToDoubleList(pCurrent);
//右子树为空
if(NULL!=pCurrent->m_pRight)
{
ergodicBSTree(pCurrent->m_pRight);
}
}
4
//二叉树转换成list
void convertToDoubleList(BSTreeNode*pCurrent)
{
pCurrent->m_pLeft=pListIndex;
if(NULL!=pListIndex)
{
pListIndex->m_pRight=pCurrent;
}
else
{
pHead=pCurrent;
}
pListIndex=pCurrent;
cout<<pCurrent->m_nValue<<endl;
}
intmain()
{
BSTreeNode*pRoot=NULL;
pListIndex=NULL;
pHead=NULL;
addBSTreeNode(pRoot,10);
addBSTreeNode(pRoot,4);
addBSTreeNode(pRoot,6);
addBSTreeNode(pRoot,8);
addBSTreeNode(pRoot,12);
addBSTreeNode(pRoot,14);
addBSTreeNode(pRoot,15);
addBSTreeNode(pRoot,16);
ergodicBSTree(pRoot);
return0;
}
///
4
6
8
10
12
14
15
16
Pressanykeytocontinue
//
5
2.设计包含min函数的栈。
定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。
要求函数min、push以及pop的时间复杂度都是O(1)。
结合链表一起做。
首先我做插入以下数字:10,7,3,3,8,5,2,6
0:10->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:2->[2](MIN=2,POS=6)如果2出栈了,那么3就是MIN
7:6->[6]
出栈的话采用类似方法修正。
所以,此题的第1小题,即是借助辅助栈,保存最小值,
且随时更新辅助栈中的元素。
如先后,push26415
stackA stackB(辅助栈)
4: 5 1 //push5,min=p->[3]=1 ^
3: 1 1 //push1,min=p->[3]=1 | //此刻push进A的元素1小于B中
栈顶元素2
2: 4 2 //push4,min=p->[0]=2 |
1: 6 2 //push6,min=p->[0]=2 |
0: 2 2 //push2,min=p->[0]=2 |
push第一个元素进A,也把它push进B,
当向Apush的元素比B中的元素小,则也push进B,即更新B。否则,不动B,保存原值。
向栈Apush元素时,顺序由下至上。
辅助栈B中,始终保存着最小的元素。
6
然后,pop栈A中元素,51462
A B->更新
4: 5 1 1 //pop5,min=p->[3]=1 |
3: 1 1 2 //pop1,min=p->[0]=2 |
2: 4 2 2 //pop4,min=p->[0]=2 |
1: 6 2 2 //pop6,min=p->[0]=2 |
0: 2 2 NULL //pop2,min=NULL v
当popA中的元素小于B中栈顶元素时,则也要popB中栈顶元素。
3.求子数组的最大和
题目:
输入一个整形数组,数组里有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
求所有子数组的和的最大值。要求时间复杂度为O(n)。
例如输入的数组为1,-2,3,10,-4,7,2,-5,和最大的子数组为3,10,-4,7,2,
因此输出为该子数组的和18。
//July2010/10/18
#include<iostream.h>
intmaxSum(int*a,intn)
{
intsum=0;
intb=0;
for(inti=0;i<n;i++)
{
if(b<0)
b=a[i];
else
b+=a[i];
if(sum<b)
sum=b;
}
7
returnsum;
}
intmain()
{
inta[10]={1,-8,6,3,-1,5,7,-2,0,1};
cout<<maxSum(a,10)<<endl;
return0;
}
运行结果,如下:
20
Pressanykeytocontinue
------------------------------------------------------------intmaxSum(int*a,intn)
{
intsum=0;
intb=0;
for(inti=0;i<n;i++)
{
if(b<=0) //此处修正下,把b<0改为b<=0
b=a[i];
else
b+=a[i];
if(sum<b)
sum=b;
}
returnsum;
}
//
解释下:
例如输入的数组为1,-2,3,10,-4,7,2,-5,
那么最大的子数组为3,10,-4,7,2,
因此输出为该子数组的和18
所有的东西都在以下俩行,
即:
8
b:0 1 -1 3 13 9 16 18 7
sum:0 1 1 3 13 13 16 18 18
其实算法很简单,当前面的几个数,加起来后,b<0后,
把b重新赋值,置为下一个元素,b=a[i]。
当b>sum,则更新sum=b;
若b<sum,则sum保持原值,不更新。:)。July、10/31。
///
关于此第3题,有网友提出,说以上的解答,
没有给出如果数组中全部为负数的情况,的解决方案。
的确,我一直把,题目限定了是既有负数也有正数的,不考虑全部为负数的情况。
当然,若考虑如果数组,全部为负数,解决方案如下(网友给出的答案,未作测试):
intmaxSum(int*a,intn)
{
intsum=0;
intb=0;
//针对数组全部为负数的判断。
intnTemp=a[0];
for(intj=1;j<n;j++)
{
if(nTemp<a[j])
nTemp=a[j];
}
if(nTemp<0)
returnnTemp;
for(inti=0;i<n;i++)
{
if(b<0)
b=a[i];
else
b+=a[i];
if(sum<b)
sum=b;
9
}
returnsum;
}
voidmain()
{
//inta[]={1,2,3,10,4,7,2,5};//
inta[]={1,-2,3,10,-4,7,2,-5};
//inta[]={-1,-2,-3,-10,-4,-7,-2,-5};
printf("\n%d\n",maxSum(a,8));
getchar();
}
//关于第4题,
当访问到某一结点时,把该结点添加到路径上,并累加当前结点的值。
如果当前结点为叶结点并且当前路径的和刚好等于输入的整数,则当前的路径符合要求,我
们把它打印出来。
如果当前结点不是叶结点,则继续访问它的子结点。当前结点访问结束后,递归函数将自动
回到父结点。
因此我们在函数退出之前要在路径上删除当前结点并减去当前结点的值,
以确保返回父结点时路径刚好是根结点到父结点的路径。
我们不难看出保存路径的数据结构实际上是一个栈结构,因为路径要与递归调用状态一致,
而递归调用本质就是一个压栈和出栈的过程。
voidFindPath
(
BinaryTreeNode* pTreeNode, //anodeofbinarytree
int expectedSum, //theexpectedsum
std::vector<int>&path, //apathfromroottocurrentnode
int& currentSum //thesumofpath
)
{
if(!pTreeNode)
return;
currentSum+=pTreeNode->m_nValue;
path.push_back(pTreeNode->m_nValue);
10
//ifthenodeisaleaf,andthesumissameaspre-defined,
//thepathiswhatwewant.printthepath
boolisLeaf=(!pTreeNode->m_pLeft&&!pTreeNode->m_pRight);
if(currentSum==expectedSum&&isLeaf)
{
std::vector<int>::iteratoriter=path.begin();
for(;iter!=path.end();++iter)
std::cout<<*iter<<'\t';
std::cout<<std::endl;
}
//ifthenodeisnotaleaf,gotoitschildren
if(pTreeNode->m_pLeft)
FindPath(pTreeNode->m_pLeft,expectedSum,path,currentSum);
if(pTreeNode->m_pRight)
FindPath(pTreeNode->m_pRight,expectedSum,path,currentSum);
//whenwefinishvisitinganodeandreturntoitsparentnode,
//weshoulddeletethisnodefromthepathand
//minusthenode'svaluefromthecurrentsum
currentSum-=pTreeNode->m_nValue;
path.pop_back();
}
5.查找最小的k个元素
题目:输入n个整数,输出其中最小的k个。
例如输入1,2,3,4,5,6,7和8这8个数字,
则最小的4个数字为1,2,3和4。
//July2010/10/18
//引用自116楼wocaoqwer的回复。
#include<iostream>
usingnamespacestd;
classMinK{
public:
MinK(int*arr,intsi):array(arr),size(si){}
boolkmin(intk,int*&ret){
11
if(k>size)
{
ret=NULL;
returnfalse;
}
else
{
ret=newint[k--];
inti;
for(i=0;i<=k;++i)
ret[i]=array[i];
for(intj=(k-1)/2;j>=0;--j)
shiftDown(ret,j,k);
for(;i<size;++i)
if(array[i]<ret[0])
{
ret[0]=array[i];
shiftDown(ret,0,k);
}
returntrue;
}
}
voidremove(int*&ret){
delete[]ret;
ret=NULL;
}
private:
voidshiftDown(int*ret,intpos,intlength){
intt=ret[pos];
for(ints=2*pos+1;s<=length;s=2*s+1){
if(s<length&&ret[s]<ret[s+1])
++s;
if(t<ret[s])
{
ret[pos]=ret[s];
pos=s;
}
elsebreak;
}
ret[pos]=t;
}
12
int*array;
intsize;
};
intmain()
{
intarray[]={1,2,3,4,5,6,7,8};
MinKmink(array,sizeof(array)/sizeof(array[0]));
int*ret;
intk=4;
if(mink.kmin(k,ret))
{
for(inti=0;i<k;++i)
cout<<ret[i]<<endl;
mink.remove(ret);
}
return0;
}
/
运行结果:
4
2
3
1
Pressanykeytocontinue
/
第6题
------------------------------------腾讯面试题:
给你10分钟时间,根据上排给出十个数,在其下排填出对应的十个数
要求下排每个数都是先前上排那十个数在下排出现的次数。
上排的十个数如下:
【0,1,2,3,4,5,6,7,8,9】
初看此题,貌似很难,10分钟过去了,可能有的人,题目都还没看懂。
13
举一个例子,
数值: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 2010年10月18日。
//数值:0,1,2,3,4,5,6,7,8,9
//分配:6,2,1,0,0,0,1,0,0,0
#include<iostream.h>
#definelen10
classNumberTB
{
private:
inttop[len];
intbottom[len];
boolsuccess;
public:
NumberTB();
int*getBottom();
voidsetNextBottom();
intgetFrequecy(intnum);
};
NumberTB::NumberTB()
{
success=false;
//formattop
for(inti=0;i<len;i++)
{
top[i]=i;
}
}
int*NumberTB::getBottom()
{
inti=0;
while(!success)
14
{
i++;
setNextBottom();
}
returnbottom;
}
//setnextbottom
voidNumberTB::setNextBottom()
{
boolreB=true;
for(inti=0;i<len;i++)
{
intfrequecy=getFrequecy(i);
if(bottom[i]!=frequecy)
{
bottom[i]=frequecy;
reB=false;
}
}
success=reB;
}
//getfrequencyinbottom
intNumberTB::getFrequecy(intnum) //此处的num即指上排的数i
{
intcount=0;
for(inti=0;i<len;i++)
{
if(bottom[i]==num)
count++;
}
returncount; //cout即对应frequecy
}
intmain()
{
NumberTBnTB;
int*result=nTB.getBottom();
for(inti=0;i<len;i++)
15
{
cout<<*result++<<endl;
}
return0;
}
///
运行结果:
6
2
1
0
0
0
1
0
0
0
Pressanykeytocontinue
/
第7题
------------------------------------微软亚院之编程判断俩个链表是否相交
给出俩个单向链表的头指针,比如h1,h2,判断这俩个链表是否相交。
为了简化问题,我们假设俩个链表均不带环。
问题扩展:
1.如果链表可能有环列?
2.如果需要求出俩个链表相交的第一个节点列?
//这一题,自己也和不少人讨论过了,
//更详细的,请看这里:
//MysinaBlog:
//http://blog.sina.com.cn/s/blog_5e3ab00c0100le4s.html
1.首先假定链表不带环
那么,我们只要判断俩个链表的尾指针是否相等。
相等,则链表相交;否则,链表不相交。
2.如果链表带环,
那判断一链表上俩指针相遇的那个节点,在不在另一条链表上。
16
如果在,则相交,如果不在,则不相交。
所以,事实上,这个问题就转化成了:
1.先判断带不带环
2.如果都不带环,就判断尾节点是否相等
3.如果都带环,判断一链表上俩指针相遇的那个节点,在不在另一条链表上。
如果在,则相交,如果不在,则不相交。
//用两个指针,一个指针步长为1,一个指针步长为2,判断链表是否有环
boolcheck(constnode*head)
{
if(head==NULL)
returnfalse;
node*low=head,*fast=head->next;
while(fast!=NULL&&fast->next!=NULL)
{
low=low->next;
fast=fast->next->next;
if(low==fast)returntrue;
}
returnfalse;
}
//如果链表可能有环,则如何判断两个链表是否相交
//思路:链表1步长为1,链表2步长为2,如果有环且相交则肯定相遇,否则不相交
list1head:p1
list2head:p2
while(p1!=p2&&p1!=NULL&&p2!=NULL)
[b]//但当链表有环但不相交时,此处是死循环。![/b]
{
p1=p1->next;
if(p2->next)
p2=p2->next->next;
else
p2=p2->next;
}
if(p1==p2&&p1&&p2)
//相交
else
//不相交
[color=#FF0000][b]所以,判断带环的链表,相不相交,只能这样[/b]:[/color]
如果都带环,判断一链表上俩指针相遇的那个节点,在不在另一条链表上。
17
如果在,则相交,如果不在,则不相交。(未写代码实现,见谅。:)..
------------------第9题
-----------------------------------判断整数序列是不是二元查找树的后序遍历结果
题目:输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果。
如果是返回true,否则返回false。
例如输入5、7、6、9、11、10、8,由于这一整数序列是如下树的后序遍历结果:
8
/\
6 10
/\/\
57911
因此返回true。
如果输入7、4、6、5,没有哪棵树的后序遍历的结果是这个序列,因此返回false。
//貌似,少有人关注此题。:).2010/10/18
boolverifySquenceOfBST(intsquence[],intlength)
{
if(squence==NULL||length<=0)
returnfalse;
//rootofaBSTisattheendofpostordertraversalsquence
introot=squence[length-1];
//thenodesinleftsub-treearelessthantheroot
inti=0;
for(;i<length-1;++i)
{
if(squence[i]>root)
break;
}
//thenodesintherightsub-treearegreaterthantheroot
intj=i;
for(;j<length-1;++j)
{
if(squence[j]<root)
returnfalse;
18
}
//verifywhethertheleftsub-treeisaBST
boolleft=true;
if(i>0)
left=verifySquenceOfBST(squence,i);
//verifywhethertherightsub-treeisaBST
boolright=true;
if(i<length-1)
right=verifySquenceOfBST(squence+i,length-i-1);
return(left&&right);
}
第9题:
其实,就是一个后序遍历二叉树的算法。
关键点:
1.
//确定根结点
introot=squence[length-1];
2.
//thenodesinleftsub-treearelessthantheroot
inti=0;
for(;i<length-1;++i)
{
if(squence[i]>root)
break;
}
//thenodesintherightsub-treearegreaterthantheroot
intj=i;
for(;j<length-1;++j)
{
if(squence[j]<root)
returnfalse;
}
3.
递归遍历,左右子树。
19
---------------------------------------//第10题,单词翻转。
//单词翻转,引用自117楼wocaoqwer的回复。
#include<iostream>
#include<string>
usingnamespacestd;
classReverseWords{
public:
ReverseWords(string*wo):words(wo){}
voidreverse_()
{
intlength=words->size();
intbegin=-1,end=-1;
for(inti=0;i<length;++i){
if(begin==-1&&words->at(i)=='')
continue;
if(begin==-1)
{
begin=i;
continue;
}
if(words->at(i)=='')
end=i-1;
elseif(i==length-1)
end=i;
else
continue;
reverse__(begin,end); //1.字母翻转
begin=-1,end=-1;
}
reverse__(0,length-1); //2.单词翻转
}
private:
voidreverse__(intbegin,intend) //
{
while(begin<end)
20
{
chart=words->at(begin);
words->at(begin)=words->at(end);
words->at(end)=t;
++begin;
--end;
}
}
string*words;
};
intmain(){
strings="I amastudent.";
ReverseWordsr(&s);
r.reverse_();
cout<<s<<endl;
return0;
}
运行结果:
student.aam I
Pressanykeytocontinue
第11题
------------------------------------求二叉树中节点的最大距离...
如果我们把二叉树看成一个图,
父子节点之间的连线看成是双向的,
我们姑且定义"距离"为两节点之间边的个数。
写一个程序,
求一棵二叉树中相距最远的两个节点之间的距离。
//July 2010/10/19
//此题思路,tree_starandi在257、258楼,讲的很明白了。
//定义一个结构体
21
structNODE
{
NODE*pLeft;
NODE*pRight;
intMaxLen;
intMaxRgt;
};
NODE*pRoot; //根节点
intMaxLength;
voidtraversal_MaxLen(NODE*pRoot)
{
if(pRoot==NULL)
{
return0;
};
if(pRoot->pLeft==NULL)
{
pRoot->MaxLeft=0;
}
else //若左子树不为空
{
intTempLen=0;
if(pRoot->pLeft->MaxLeft>pRoot->pLeft->MaxRight)
//左子树上的,某一节点,往左边大,还是往右边大
{
TempLen+=pRoot->pLeft->MaxLeft;
}
else
{
TempLen+=pRoot->pLeft->MaxRight;
}
pRoot->nMaxLeft=TempLen+1;
traversal_MaxLen(NODE*pRoot->pLeft);
//此处,加上递归
}
if(pRoot->pRigth==NULL)
{
pRoot->MaxRight=0;
}
else //若右子树不为空
22
{
intTempLen=0;
if(pRoot->pRight->MaxLeft>pRoot->pRight->MaxRight)
//右子树上的,某一节点,往左边大,还是往右边大
{
TempLen+=pRoot->pRight->MaxLeft;
}
else
{
TempLen+=pRoot->pRight->MaxRight;
}
pRoot->MaxRight=TempLen+1;
traversal_MaxLen(NODE*pRoot->pRight);
//此处,加上递归
}
if(pRoot->MaxLeft+pRoot->MaxRight>0)
{
MaxLength=pRoot->nMaxLeft+pRoot->MaxRight;
}
}
//数据结构定义
structNODE
{
NODE*pLeft; //左子树
NODE*pRight; //右子树
intnMaxLeft; //左子树中的最长距离
intnMaxRight; //右子树中的最长距离
charchValue; //该节点的值
};
intnMaxLen=0;
//寻找树中最长的两段距离
voidFindMaxLen(NODE*pRoot)
{
//遍历到叶子节点,返回
if(pRoot==NULL)
{
return;
}
23
//如果左子树为空,那么该节点的左边最长距离为0
if(pRoot->pLeft==NULL)
{
pRoot->nMaxLeft=0;
}
//如果右子树为空,那么该节点的右边最长距离为0
if(pRoot->pRight==NULL)
{
pRoot->nMaxRight=0;
}
//如果左子树不为空,递归寻找左子树最长距离
if(pRoot->pLeft!=NULL)
{
FindMaxLen(pRoot->pLeft);
}
//如果右子树不为空,递归寻找右子树最长距离
if(pRoot->pRight!=NULL)
{
FindMaxLen(pRoot->pRight);
}
//计算左子树最长节点距离
if(pRoot->pLeft!=NULL)
{
intnTempMax=0;
if(pRoot->pLeft->nMaxLeft>pRoot->pLeft->nMaxRight)
{
nTempMax=pRoot->pLeft->nMaxLeft;
}
else
{
nTempMax=pRoot->pLeft->nMaxRight;
}
pRoot->nMaxLeft=nTempMax+1;
}
//计算右子树最长节点距离
if(pRoot->pRight!=NULL)
{
intnTempMax=0;
if(pRoot->pRight->nMaxLeft>pRoot->pRight->nMaxRight)
24
{
nTempMax=pRoot->pRight->nMaxLeft;
}
else
{
nTempMax=pRoot->pRight->nMaxRight;
}
pRoot->nMaxRight=nTempMax+1;
}
//更新最长距离
if(pRoot->nMaxLeft+pRoot->nMaxRight>nMaxLen)
{
nMaxLen=pRoot->nMaxLeft+pRoot->nMaxRight;
}
}
//很明显,思路完全一样,但书上给的这段代码更规范!:)。
第12题
题目:求1+2+…+n,
要求不能使用乘除法、for、while、if、else、switch、case等关键字
以及条件判断语句(A?B:C)。
//July、2010/10/19
-----------------循环只是让相同的代码执行n遍而已,我们完全可以不用for和while达到这个效果。
比如定义一个类,我们new一含有n个这种类型元素的数组,
那么该类的构造函数将确定会被调用n次。我们可以将需要执行的代码放到构造函数里。
------------------#include<iostream.h>
classTemp
{
public:
Temp()
{
++N;
25
Sum+=N;
}
staticvoidReset(){N=0;Sum=0;}
staticintGetSum(){returnSum;}
private:
staticintN;
staticintSum;
};
intTemp::N=0;
intTemp::Sum=0;
intsolution1_Sum(intn)
{
Temp::Reset();
Temp*a=newTemp[n]; //就是这个意思,new出n个数组。
delete[]a;
a=0;
returnTemp::GetSum();
}
intmain()
{
cout<<solution1_Sum(100)<<endl;
return0;
}
//运行结果:
//5050
//Pressanykeytocontinue
//July、2010/10/19
//第二种思路:
----------------既然不能判断是不是应该终止递归,我们不妨定义两个函数。
一个函数充当递归函数的角色,另一个函数处理终止递归的情况,
我们需要做的就是在两个函数里二选一。
26
从二选一我们很自然的想到布尔变量,
比如ture/(1)的时候调用第一个函数,false/(0)的时候调用第二个函数。
那现在的问题是如和把数值变量n转换成布尔值。
如果对n连续做两次反运算,即!!n,那么非零的n转换为true,0转换为false。
#include<iostream.h>
classA;
A*Array[2];
classA
{
public:
virtualintSum(intn){return0;}
};
classB:publicA
{
public:
virtualintSum(intn){returnArray[!!n]->Sum(n-1)+n;}
};
intsolution2_Sum(intn)
{
Aa;
Bb;
Array[0]=&a;
Array[1]=&b;
intvalue=Array[1]->Sum(n);
//利用虚函数的特性,当Array[1]为0时,即Array[0]=&a;执行A::Sum,
//当Array[1]不为0时, 即Array[1]=&b;执行B::Sum。
returnvalue;
}
intmain()
{
cout<<solution2_Sum(100)<<endl;
return0;
}
27
//5050
//Pressanykeytocontinue
第13题:
题目:
输入一个单向链表,输出该链表中倒数第k个结点,
链表的倒数第0个结点为链表的尾指针。
//此题一出,相信,稍微有点经验的同志,都会说到:
------------------------设置两个指针p1,p2
首先p1和p2都指向head
然后p2向前走n步,这样p1和p2之间就间隔k个节点
然后p1和p2同……
#include<iostream.h>
#include<stdio.h>
#include<stdlib.h>
structListNode
{
chardata;
ListNode*next;
};
ListNode*head,*p,*q;
ListNode*pone,*ptwo;
ListNode*fun(ListNode*head,intk)
{
pone=ptwo=head;
for(inti=0;i<=k-1;i++)
ptwo=ptwo->next;
while(ptwo!=NULL)
{
pone=pone->next;
ptwo=ptwo->next;
}
returnpone;
}
28
intmain()
{
charc;
head=(ListNode*)malloc(sizeof(ListNode));
head->next=NULL;
p=head;
while(c!='0')
{
q=(ListNode*)malloc(sizeof(ListNode));
q->data=c;
q->next=NULL;
p->next=q;
p=p->next;
c=getchar();
}
cout<<"---------------"<<endl;
cout<<fun(head,2)->data<<endl;
return0;
}
/
1254863210
---------------2
Pressanykeytocontinue

第14题:
题目:输入一个已经按升序排序过的数组和一个数字,
在数组中查找两个数,使得它们的和正好是输入的那个数字。
要求时间复杂度是O(n)。
如果有多对数字的和等于输入的数字,输出任意一对即可。
例如输入数组1、2、4、7、11、15和数字15。由于4+11=15,因此输出4和11。
//由于数组已经过升序排列,所以,难度下降了不少。
//July、2010/10/19
#include<iostream.h>
29
boolFindTwoNumbersWithSum
(
intdata[], //已经排序的数组
unsignedintlength, //数组长度
intsum, //用户输入的sum
int&num1, //输出符合和等于sum的第一个数
int&num2 //第二个数
)
{
boolfound=false;
if(length<1)
returnfound;
intbegin=0;
intend=length-1;
while(end>begin)
{
longcurSum=data[begin]+data[end];
if(curSum==sum)
{
num1=data[begin];
num2=data[end];
found=true;
break;
}
elseif(curSum>sum)
end--;
else
begin++;
}
returnfound;
}
intmain()
{
intx,y;
inta[6]={1,2,4,7,11,15};
if(FindTwoNumbersWithSum(a,6,15,x,y))
{
cout<<x<<endl<<y<<endl;
30
}
return0;
}
4
11
Pressanykeytocontinue
//扩展:如果输入的数组是没有排序的,但知道里面数字的范围,其他条件不变,
//如何在O(n)时间里找到这两个数字?
关于第14题,
1.题目假定是,只要找出俩个数,的和等于给定的数,
其实是,当给定一排数,
4,5,7,10,12
然后给定一个数,22。
就有俩种可能了。因为22=10+12=10+5+7。
而恰恰与第4题,有关联了。望大家继续思考下。:)。
2.第14题,还有一种思路,如下俩个数组:
1、2、4、7、11、15 //用15减一下为
14、13、11、8、4、0 //如果下面出现了和上面一样的数,稍加判断,就能找出这俩
个数来了。
第一个数组向右扫描,第二个数组向左扫描。
第15题:
题目:输入一颗二元查找树,将该树转换为它的镜像,
即在转换后的二元查找树中,左子树的结点都大于右子树的结点。
用递归和循环两种方法完成树的镜像转换。
例如输入:
8
/\
6 10
/\/\
57911
输出:
31
8
/\
10 6
/\/\
1197 5
定义二元查找树的结点为:
structBSTreeNode//anodeinthebinarysearchtree(BST)
{
intm_nValue;//valueofnode
BSTreeNode*m_pLeft;//leftchildofnode
BSTreeNode*m_pRight;//rightchildofnode
};
//就是递归翻转树,有子树则递归翻转子树。
//July、2010/10/19
voidRevertsetree(list*root)
{
if(!root)
return;
list*p;
p=root->leftch;
root->leftch=root->rightch;
root->rightch=p;
if(root->leftch)
Revertsetree(root->leftch);
if(root->rightch)
Revertsetree(root->rightch);
}
由于递归的本质是编译器生成了一个函数调用的栈,
因此用循环来完成同样任务时最简单的办法就是用一个辅助栈来模拟递归。
首先我们把树的头结点放入栈中。
在循环中,只要栈不为空,弹出栈的栈顶结点,交换它的左右子树。
如果它有左子树,把它的左子树压入栈中;
如果它有右子树,把它的右子树压入栈中。
32
这样在下次循环中就能交换它儿子结点的左右子树了。
//再用辅助栈模拟递归,改成循环的(有误之处,望不吝指正):
voidRevertsetree(list*phead)
{
if(!phead)
return;
stack<list*>stacklist;
stacklist.push(phead); //首先把树的头结点放入栈中。
while(stacklist.size())
//在循环中,只要栈不为空,弹出栈的栈顶结点,交换它的左右子树
{
list*pnode=stacklist.top();
stacklist.pop();
list*ptemp;
ptemp=pnode->leftch;
pnode->leftch=pnode->rightch;
pnode->rightch=ptemp;
if(pnode->leftch)
stacklist.push(pnode->leftch); //若有左子树,把它的左子树压入栈中
if(pnode->rightch)
stacklist.push(pnode->rightch); //若有右子树,把它的右子树压入栈中
}
}
第16题
题目:输入一颗二元树,从上往下按层打印树的每个结点,同一层中按照从左往右的顺序打
印。
例如输入
8
/ \
6 10
/\ /\
5 7 9 11
33
输出8 6 10 5 7 9 11。
//题目不是我们所熟悉的,树的前序,中序,后序。即是树的层次遍历。
/*308楼panda_lin的回复,说的已经很好了。:)
利用队列,每个单元对应二叉树的一个节点.
1:输出8,队列内容:6,10
2:输出6, 6的2个子节点5,7入队列。队列的内容:10,5,7
3:输出10,10的2个子节点9,11入队列。队列的内容:5,7,9,11。
4:输出5,5没有子节点。队列的内容:7,9,11
5:。。。
由于STL已经为我们实现了一个很好的deque(两端都可以进出的队列),
我们只需要拿过来用就可以了。
我们知道树是图的一种特殊退化形式。
同时如果对图的深度优先遍历和广度优先遍历有比较深刻的理解,
将不难看出这种遍历方式实际上是一种广度优先遍历。
因此这道题的本质是在二元树上实现广度优先遍历。
//July、2010/10/19/晚。
#include<deque>
#include<iostream>
usingnamespacestd;
structBTreeNode//anodeinthebinarytree
{
int m_nValue;//valueofnode
BTreeNode *m_pLeft; //leftchildofnode
BTreeNode *m_pRight;//rightchildofnode
};
BTreeNode*pListIndex;
BTreeNode*pHead;
voidPrintFromTopToBottom(BTreeNode*pTreeRoot)
{
if(!pTreeRoot)
return;
//getaemptyqueue
deque<BTreeNode*>dequeTreeNode;
//inserttherootatthetailofqueue
34
dequeTreeNode.push_back(pTreeRoot);
while(dequeTreeNode.size())
{
//getanodefromtheheadofqueue
BTreeNode*pNode=dequeTreeNode.front();
dequeTreeNode.pop_front();
//printthenode
cout<<pNode->m_nValue<<'';
//printitsleftchildsub-treeifithas
if(pNode->m_pLeft)
dequeTreeNode.push_back(pNode->m_pLeft);
//printitsrightchildsub-treeifithas
if(pNode->m_pRight)
dequeTreeNode.push_back(pNode->m_pRight);
}
}
//创建二元查找树
voidaddBTreeNode(BTreeNode*&pCurrent,intvalue)
{
if(NULL==pCurrent)
{
BTreeNode*pBTree=newBTreeNode();
pBTree->m_pLeft=NULL;
pBTree->m_pRight=NULL;
pBTree->m_nValue=value;
pCurrent=pBTree;
}
else
{
if((pCurrent->m_nValue)>value)
{
addBTreeNode(pCurrent->m_pLeft,value);
}
elseif((pCurrent->m_nValue)<value)
{
addBTreeNode(pCurrent->m_pRight,value);
}
}
}
35
intmain()
{
BTreeNode*pRoot=NULL;
pListIndex=NULL;
pHead=NULL;
addBTreeNode(pRoot,8);
addBTreeNode(pRoot,6);
addBTreeNode(pRoot,5);
addBTreeNode(pRoot,7);
addBTreeNode(pRoot,10);
addBTreeNode(pRoot,9);
addBTreeNode(pRoot,11);
PrintFromTopToBottom(pRoot);
return0;
}
//输出结果:
//861057911Pressanykeytocontinue
是的,由这道题,突然想到了,树的广度优先遍历,BFS算法,
算法王帖:精选经典的24个算法[3.BFS和DFS优先搜索]
http://blog.sina.com.cn/s/blog_5e3ab00c0100lya2.html
第17题:
题目:在一个字符串中找到第一个只出现一次的字符。
如输入abaccdeff,则输出b。
这道题是2006年google的一道笔试题。
思路剖析:由于题目与字符出现的次数相关,我们可以统计每个字符在该字符串中出现的次
数.
要达到这个目的,需要一个数据容器来存放每个字符的出现次数。
在这个数据容器中可以根据字符来查找它出现的次数,
也就是说这个容器的作用是把一个字符映射成一个数字。
在常用的数据容器中,哈希表正是这个用途。
由于本题的特殊性,我们只需要一个非常简单的哈希表就能满足要求。
36
由于字符(char)是一个长度为8的数据类型,因此总共有可能256种可能。
于是我们创建一个长度为256的数组,每个字母根据其ASCII码值作为数组的下标对应数组
的对应项,
而数组中存储的是每个字符对应的次数。
这样我们就创建了一个大小为256,以字符ASCII码为键值的哈希表。
我们第一遍扫描这个数组时,每碰到一个字符,在哈希表中找到对应的项并把出现的次数增
加一次。
这样在进行第二次扫描时,就能直接从哈希表中得到每个字符出现的次数了。
//July、2010/10/20
#include<iostream.h>
#include<string.h>
charFirstNotRepeatingChar(char*pString)
{
if(!pString)
return0;
constinttableSize=256;
unsignedinthashTable[tableSize];
for(unsignedinti=0;i<tableSize;++i)
hashTable[i]=0;
char*pHashKey=pString;
while(*(pHashKey)!='\0')
hashTable[*(pHashKey++)]++;
pHashKey=pString;
while(*pHashKey!='\0')
{
if(hashTable[*pHashKey]==1)
return*pHashKey;
pHashKey++;
}
return*pHashKey;
}
intmain()
{
cout<<"请输入一串字符:"<<endl;
37
chars[100];
cin>>s;
char*ps=s;
cout<<FirstNotRepeatingChar(ps)<<endl;
return0;
}
//
请输入一串字符:
abaccdeff
b
Pressanykeytocontinue
///
第18题:
题目:n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始,
每次从这个圆圈中删除第m个数字(第一个为当前数字本身,第二个为当前数字的下一个数
字)。
当一个数字删除后,从被删除数字的下一个继续删除第m个数字。
求出在这个圆圈中剩下的最后一个数字。
July:我想,这个题目,不少人已经见识过了。
先看这个题目的简单变形。
n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),
凡报到3的人退出圈子,问最后留下的是原来第几号的那个人?
---------------------------------------------------------//July、2010/10/20
//我把这100题,当每日必须完成的作业,来做了。:)。
#include<stdio.h>
intmain()
{
inti,k,m,n,num[50],*p;
printf("inputnumberofperson:n=");
scanf("%d",&n);
printf("inputnumberofthequit:m="); //留下->18题
scanf("%d",&m); //留下->18题
38
p=num;
for(i=0;i<n;i++)
*(p+i)=i+1; //给每个人编号
i=0; //报数
k=0; //此处为3
// m=0; //m为退出人数 //去掉->18题
while(m<n-1)
{
if(*(p+i)!=0)
k++;
if(k==3)
{
*(p+i)=0; //退出,对应的数组元素置为0
k=0;
m++;
}
i++;
if(i==n)
i=0;
}
while(*p==0)
p++;
printf("ThelastoneisNO.%d\n",*p);
}
//
intLastRemaining_Solution2(intn,unsignedintm)
{
//invalidinput
if(n<=0||m<0)
return-1;
//ifthereareonlyoneintegerinthecircleinitially,
//ofcoursethelastremainingoneis0
intlastinteger=0;
//findthelastremainingoneinthecirclewithnintegers
for(inti=2;i<=n;i++)
lastinteger=(lastinteger+m)%i;
returnlastinteger;
}

39
第19题:
题目:定义Fibonacci数列如下:
/ 0 n=0
f(n)=1 n=1,2
\f(n-1)+f(n-2) n>2
输入n,用最快的方法求该数列的第n项。
分析:在很多C语言教科书中讲到递归函数的时候,都会用Fibonacci作为例子。
因此很多程序员对这道题的递归解法非常熟悉,但....呵呵,你知道的。。
//01235813213455891442333776109871597..........
//注意,当求第100项,甚至更大的项时,请确保你用什么类型,长整型?orlonglongint
存储。
//不然,计算机,将得不到结果。
//若用递归方法,可写下如下代码:
#include<iostream.h>
intFibona(intn)
{
intm;
if(n==0)
return0;
elseif(n==1||n==2)
return1;
else
{
m=Fibona(n-1)+Fibona(n-2);
returnm;
}
}
intmain()
{
40
cout<<"-----------------"<<endl;
cout<<Fibona(17)<<endl;
return0;
}
---------------------------科书上反复用这个题目来讲解递归函数,并不能说明递归解法最适合这道题目。
我们以求解f(10)作为例子来分析递归求解的过程。
要求得f(10),需要求得f(9)和f(8)。同样,要求得f(9),要先求得f(8)和f(7)……
我们用树形结构来表示这种依赖关系
f(10)
/ \
f(9) f(8)
/ \ / \
f(8) f(7) f(6) f(5)
/ \ / \
f(7) f(6) f(6)f(5)
更简单的办法是从下往上计算,首先根据f(0)和f(1)算出f(2),再根据f(1)和f(2)算出
f(3)……
依此类推就可以算出第n项了。很容易理解,这种思路的时间复杂度是O(n)。
其实,就是转化为非递归程序,用递推。!
------------------------------------------longlongFibonacci_Solution2(unsignedn)
{
intresult[2]={0,1};
if(n<2)
returnresult[n];
longlong fibNMinusOne=1;
longlong fibNMinusTwo=0;
longlong fibN=0;
for(unsignedinti=2;i<=n;++i)
{
fibN=fibNMinusOne+fibNMinusTwo;
fibNMinusTwo=fibNMinusOne;
fibNMinusOne=fibN;
}
41
returnfibN;
}
//很可惜,这还不是最快的方法。
//还有一种方法,可达到,时间复杂度为O(lgn).
//............
第20题:
题目:输入一个表示整数的字符串,把该字符串转换成整数并输出。
例如输入字符串"345",则输出整数345。
-----------------------------此题一点也不简单。不信,你就先不看一下的代码,
你自己先写一份,然后再对比一下,便知道了。
1.转换的思路:每扫描到一个字符,我们把在之前得到的数字乘以10再加上当前字符表示的
数字。
这个思路用循环不难实现。
2.由于整数可能不仅仅之含有数字,还有可能以'+'或者'-'开头,表示整数的正负。
如果第一个字符是'+'号,则不需要做任何操作;如果第一个字符是'-'号,
则表明这个整数是个负数,在最后的时候我们要把得到的数值变成负数。
3.接着我们试着处理非法输入。由于输入的是指针,在使用指针之前,
我们要做的第一件是判断这个指针是不是为空。
如果试着去访问空指针,将不可避免地导致程序崩溃。
4.输入的字符串中可能含有不是数字的字符。
每当碰到这些非法的字符,我们就没有必要再继续转换。
最后一个需要考虑的问题是溢出问题。由于输入的数字是以字符串的形式输入,
因此有可能输入一个很大的数字转换之后会超过能够表示的最大的整数而溢出。
//July、2010、10/22。
enumStatus{kValid=0,kInvalid};
intg_nStatus=kValid;
intStrToInt(constchar*str)
{
g_nStatus=kInvalid;
longlongnum=0;
if(str!=NULL)
42
{
constchar*digit=str;
//thefirstcharinthestringmaybe'+'or'-'
boolminus=false;
if(*digit=='+')
digit++;
elseif(*digit=='-')
{
digit++;
minus=true;
}
//theremainingcharsinthestring
while(*digit!='\0')
{
if(*digit>='0'&&*digit<='9')
{
num=num*10+(*digit-'0');
//overflow
if(num>std::numeric_limits<int>::max())
{
num=0;
break;
}
digit++;
}
//ifthecharisnotadigit,invalidinput
else
{
num=0;
break;
}
}
if(*digit=='\0')
{
g_nStatus=kValid;
if(minus)
num=0-num;
}
}
returnstatic_cast<int>(num);
43
}
//在C语言提供的库函数中,函数atoi能够把字符串转换整数。
//它的声明是intatoi(constchar*str)。该函数就是用一个全局变量来标志输入是否合

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值