程序員面試100題_第1頁
程序員面試100題_第2頁
程序員面試100題_第3頁
程序員面試100題_第4頁
程序員面試100題_第5頁
已閱讀5頁,還剩97頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

http:〃zhedahht.blog.163.com/blog/static/254111742007127104759245/

(01)一把二元查找樹轉(zhuǎn)變成排序的雙向鏈表......................................1

(02)一設(shè)計(jì)包含min函數(shù)的棧..................................................5

(03)一求子數(shù)組的最大和......................................................8

(04)一在二元樹中找出和為某一值的所有路徑...................................10

(05)一查找最小的k個(gè)元素....................................................11

(06)一判斷整數(shù)序列是不是二元查找樹的后序遍歷結(jié)果..........................13

(07)一翻轉(zhuǎn)句子中單詞的順序..................................................15

(08)-求l+2+...+n............................................................17

(09)一查找鏈表中倒數(shù)第k個(gè)結(jié)點(diǎn).............................................20

(10)一在排序數(shù)組中查找和為給定值的兩個(gè)數(shù)字................................23

(11)一求二元查找樹的鏡像...................................................25

(12)一從上往下遍歷二元樹...................................................28

(13)—第一個(gè)只出現(xiàn)一次的字符...............................................30

(14)一圓圈中最后剩下的數(shù)字.................................................33

(15)一含有指針成員的類的拷貝...............................................37

(16)—O(logn)求Fibonacci數(shù)列................................................40

(17)一把字符串轉(zhuǎn)換成整數(shù)...................................................45

(18)一用兩個(gè)棧實(shí)現(xiàn)隊(duì)列.....................................................47

(19)一反轉(zhuǎn)鏈表..............................................................50

(20)一最長公共子串(太難懂)...............................................51

(21)一左旋轉(zhuǎn)字符串(精彩).................................................56

(22)一整數(shù)的二進(jìn)制表示中1的個(gè)數(shù)...........................................57

(23)一跳臺(tái)階問題............................................................60

(24)一棧的push、pop序列...................................................60

(25)-在從1到n的正數(shù)中1出現(xiàn)的次數(shù)(不懂)................................63

(26)-和為n連續(xù)正數(shù)序列(不錯(cuò))............................................67

(27)-二元樹的深度...........................................................70

(28)-字符串的排列(暫時(shí)還不懂)............................................72

(29)-調(diào)整數(shù)組順序使奇數(shù)位于偶數(shù)前面........................................74

(30)-異常安全的賦值運(yùn)算符重載函數(shù)..........................................77

(01)一把二元查找樹轉(zhuǎn)變成排序的雙向鏈表

題目:輸入一棵二元查找樹,籽該二元查找樹轉(zhuǎn)換成一個(gè)排序的雙向鏈表。要求不能創(chuàng)建任何新的

結(jié)點(diǎn),只調(diào)整指針的指向。

比如將二元查找樹

10

/\

614

481216

轉(zhuǎn)換成雙向鏈表

4=6=8=10=12=14=16o

分析:本題是微軟的面試題。很多與樹相關(guān)的題目都是用遞歸的思路來解決,本題也不例外。下面

我們用兩種不同的遞歸思路來分析。

思路一:當(dāng)我們到達(dá)某一結(jié)點(diǎn)準(zhǔn)備調(diào)整以該結(jié)點(diǎn)為根結(jié)點(diǎn)的子樹時(shí),先調(diào)整其左子樹將左子樹轉(zhuǎn)換

成一個(gè)排好序的左子鏈表,再調(diào)整其右子樹轉(zhuǎn)換右子鏈表。最近鏈接左子鏈表的最右結(jié)點(diǎn)(左子樹的最大

結(jié)點(diǎn))、當(dāng)前結(jié)點(diǎn)和右子鏈表的最左結(jié)點(diǎn)(右子樹的最小結(jié)點(diǎn))。從樹的根結(jié)點(diǎn)開始遞歸調(diào)整所有結(jié)點(diǎn)。

思路二:我們可以中序遍歷整棵樹。按照這個(gè)方式遍歷樹,比較小的結(jié)點(diǎn)先訪問。如果我們每訪問

一個(gè)結(jié)點(diǎn),假設(shè)之前訪問過的結(jié)點(diǎn)已經(jīng)調(diào)整成一個(gè)排序雙向鏈表,我們再把調(diào)整當(dāng)前結(jié)點(diǎn)的指針將其鏈接

到鏈表的末尾。當(dāng)所有結(jié)點(diǎn)都訪問過之后,整棵樹也就轉(zhuǎn)換成一個(gè)排序雙向鏈表了。

參考代碼:

首先我們定義二元查找樹結(jié)點(diǎn)的數(shù)據(jù)結(jié)構(gòu)如F:

structBSTreeNode//anodeinthebinarysearchtree

(

intm_nValue;//valueofnode

BSTreeNode*m_pLeft;//leftchildofnode

BSTreeNode*m_pRight;//rightchildofnode

);

思路一對(duì)應(yīng)的代碼:

/////////////////////////////////////////////////////////////////////

//

//Covertasubbinary-search-treeintoasorteddouble-linkedlist

//Input:pNode-theheadofthesubtree

//asRight-whetherpNodeistherightchildofitsparent

//Output:ifasRightistrue,returntheleastnodeinthesub-tree

//elsereturnthegreatestnodeinthesub-tree

/////////////////////////////////////////////////////////////////////

//

BSTreeNode*ConvertNode(BSTreeNode*pNode,boolasRight)

(

if(!pNode)

returnNULL;

BSTreeNode*pLeft=NULL;

BSTreeNode*pRight=NULL;

//Converttheleftsub-tree

if(pNode->m_pLeft)

pLeft=ConvertNode(pNode->m_pLeftzfalse);

//Connectthegreatestnodeintheleftsub-treetothecurrentnode

if(pLeft)

{

pLeft->m_pRight=pNode;

pNode->m_pLeft=pLeft;

}

//Converttherightsub-tree

if(pNode->m_pRight)

pRight=ConvertNode(pNode->m_pRightftrue);

//Connecttheleastnodeintherightsub-treetothecurrentnode

if(pRight)

{

pNode->m_pRight=pRight;

pRight->m_pLeft=pNode;

)

BSTreeNode*pTennp=pNode;

//Ifthecurrentnodeistherightchildofitsparent,

//returntheleastnodeinthetreewhoserootisthecurrentnode

if(asRight)

{

while(pTemp->m_pLeft)

pTemp=pTemp->m_pLeft;

)

//Ifthecurrentnodeistheleftchildofitsparent,

//returnthegreatestnodeinthetreewhoserootisthecurrentnode

else

{

while(pTemp->m_pRight)

pTemp=pTemp->m_pRight;

)

returnpTemp;

}

/////////////////////////////////////////////////////////////////////

//

//Covertabinarysearchtreeintoasorteddouble-linkedlist

//Input:theheadoftree

//Output:theheadofsorteddouble-linkedlist

/////////////////////////////////////////////////////////////////////

//

BSTreeNode*Convert(BSTreeNode*pHeadOfTree)

(

//Aswewanttoreturntheheadofthesorteddouble-linkedlist,

//wesetthesecondparametertobetrue

returnConvertNode(pHeadOfTree,true);

}

思路二對(duì)應(yīng)的代碼:

/////////////////////////////////////////////////////////////////////

//

//Covertasubbinary-search-treeintoasorteddouble-linkedlist

//Input:pNode-theheadofthesubtree

//pLastNodelnList-thetailofthedouble-linkedlist

/////////////////////////////////////////////////////////////////////

//

voidConvertNode(BSTreeNode*pNode,BSTreeNode*&pLastNodelnList)

(

if(pNode==NULL)

return;

BSTreeNode*pCurrent=pNode;

//Converttheleftsub-tree

if(pCurrent->m_pLeft!=NULL)

ConvertNode(pCurrent->m_pLeftzpLastNodelnList);

//Putthecurrentnodeintothedouble-linkedlist

pCurrent->m_pLeft=pLastNodelnList;

if(pLastNodelnList!=NULL)

pLastNodeInList->m_pRight=pCurrent;

pLastNodelnList=pCurrent;

//Converttherightsub-tree

if(pCurrent->m__pRight!=NULL)

ConvertNode(pCurrent->m_pRightzpLastNodelnList);

}

/////////////////////////////////////////////////////////////////////

//

//Covertabinarysearchtreeintoasorteddouble-linkedlist

//Input:pHeadOfTree-theheadoftree

//Output:theheadofsorteddouble-linkedlist

/////////////////////////////////////////////////////////////////////

//

BSTreeNode*Convert_Solutionl(BSTreeNode*pHeadOfTree)

(

BSTreeNode*pLastNodeInList=NULL;

ConvertNode(pHeadOfTree,pLastNodelnList);

//Gettheheadofthedouble-linkedlist

BSTreeNode*pHeadOfList=pLastNodelnList;

while(pHeadOfList&&pHeadOfList->m_pLeft)

pHeadOfList=pHeadOfList->m__pLeft;

returnpHeadOfList;

}

(02)一設(shè)計(jì)包含min函數(shù)的棧

題口:定義棧的數(shù)據(jù)結(jié)構(gòu),要求添加一個(gè)min函數(shù),能夠得到棧的最小元素。要求函數(shù)min、push以及

pop的時(shí)間復(fù)雜度都是0(1)。

分析:這是去年google的一道面試題。

我看到這道題目時(shí),第一反應(yīng)就是每次push一個(gè)新元素時(shí),將棧里所有逆序元素排序。這樣棧頂元素將是

最小元素。但由于不能保證最后push進(jìn)棧的元素最先出棧,這種思路設(shè)計(jì)的數(shù)據(jù)結(jié)構(gòu)已經(jīng)不是一個(gè)棧了。

在棧里添加一個(gè)成員變量存放最小元素(或最小元素的位置)。每次push一個(gè)新元素進(jìn)棧的時(shí)候,如果該

元素比當(dāng)前的最小元素還要小,則更新最小元素。

乍?看這樣思路挺好的。但仔細(xì)想,該思路存在個(gè)重要的問題:如果當(dāng)前最小元素被pop出去,如何

才能得到下?個(gè)最小元素?

因此僅僅只添加一個(gè)成員變量存放最小元素(或最小元素的位置)是不夠的。我們需要一個(gè)輔助棧。每次

push?個(gè)新元素的時(shí)候,同時(shí)將最小元素(或最小元素的位置。考慮到棧元素的類型可能是復(fù)雜的數(shù)據(jù)結(jié)

構(gòu),用最小元素的位置將能減少空間消耗)push到輔助棧中;每次pop一個(gè)元素出棧的時(shí)候,同時(shí)pop

輔助棧。

參考代碼:

#include<deque>

#include<assert.h>

template<typenameT>classCStackWithMin

(

public:

CStackWithMin(void){}

virtual-CStackWithMin(void){}

T&top(void);

constT&top(void)const;

voidpush(constT&value);

voidpop(void);

constT&min(void)const;

private:

T>m_data;//theelementsofstack

size_t>m_minIndex;//theindicesofminimumelements

};

//getthelastelementofmutablestack

template<typenameT>T&CStackWithMin<T>::top()

(

returnm_data.back();

}

//getthelastelementofnon-mutablestack

template<typenameT>constT&CStackWithMin<T>::top()const

(

returnm_data.back();

}

//insertanelmentattheendofstack

template<typenameT>voidCStackWithMin<T>::push(constT&value)

{

//appendthedataintotheendofm_data

m_data.push_back(value);

//settheindexofminimumelmentinm_dataattheendofm_minlndex

if(m_minIndex.size()==0)

m_minlndex.push_back(0);

else

if(value<m__data[rn_minlndex.back()])

m_minlndex.push_back(m_data.size()-1);

else

m_minlndex.push_back(m_minlnciex.back());

)

}

//ereasetheelementattheendofstack

template〈typenameT>voidCStackWithMin<T>::pop()

(

//popm_data

m_data.pop_back();

//popm_minIndex

m_minIndex.pop_back.();

)

//gettheminimumelementofstack

template<typenameT>constT&CStackWithMin<T>::min()const

(

assert(m_data.size()>0);

assert(m_minlndex.size()>0);

returnm_data[m_minIndex.back()];

}

舉個(gè)例子演示上述代碼的運(yùn)行過程:

步驟數(shù)據(jù)棧輔助棧最小值

1.push3303

2.push43,40,03

3.push23,4,20,0,22

4.push13,4,2,10,0,2,31

5.pop3,4,20,0,22

6.pop3,40,03

7.push03,4,00,0,20

討論:如果思路正確,編寫上述代碼不是一件很難的事情。但如果能注意一些細(xì)節(jié)無疑能在面試中加分。

比如我在上面的代碼中做了如下的工作:

?用模板類實(shí)現(xiàn)。如果別人的元素類型只是int類型,模板將能給面試官帶來好印象;

?兩個(gè)版本的top函數(shù)。在很多類中,都需要提供const和非const版本的成員訪問函數(shù);

?min函數(shù)中assert,把代碼寫的盡量安全是每個(gè)軟件公司對(duì)程序員的要求;

?添加一些注釋。注釋既能提高代碼的可讀性,又能增加代碼量,何樂而不為?

總之,在面試時(shí)如果時(shí)間允許,盡量把代碼寫的漂亮一些。說不定代碼中的兒個(gè)小亮點(diǎn)就能讓自己輕松拿

到心儀的Offer,

(03)一求子數(shù)組的最大和

題目:輸入個(gè)整形數(shù)組,數(shù)組里有正數(shù)也有負(fù)數(shù)。數(shù)組中連續(xù)的?個(gè)或多個(gè)整數(shù)組成?個(gè)子數(shù)組,每個(gè)

子數(shù)組都有?個(gè)和。求所有子數(shù)組的和的最大值。要求時(shí)間復(fù)雜度為0(n)。

例如輸入的數(shù)組為1,-2,3,10,-4,7,2,-5,和最大的子數(shù)組為3,10,-4,7,2,因此輸出為該子數(shù)組的和

18o

分析:本題最初為2005年浙江大學(xué)計(jì)算機(jī)系的考研題的最后一道程序設(shè)計(jì)題,在2006年里包括google

在內(nèi)的很多知名公司都把本題當(dāng)作面試題。由于本題在網(wǎng)絡(luò)中廣為流傳,本題也順利成為2006年程序員

面試題中經(jīng)典中的經(jīng)典。

如果不考慮時(shí)間復(fù)雜度,我們可以枚舉出所有子數(shù)組并求出他們的和。不過非常遺憾的是,由于長度為n

的數(shù)組有。(產(chǎn))個(gè)子數(shù)組;而且求?個(gè)長度為n的數(shù)組的和的時(shí)間復(fù)雜度為0(n)。因此這種思路的時(shí)間是

O(n3)o

很容易理解,當(dāng)我們加上一個(gè)正數(shù)時(shí),和會(huì)增加;當(dāng)我們加上一個(gè)負(fù)數(shù)時(shí),和會(huì)減少。如果當(dāng)前得到的和

是個(gè)負(fù)數(shù),那么這個(gè)和在接下來的累加中應(yīng)該拋棄并重新清零,不然的話這個(gè)負(fù)數(shù)將會(huì)減少接下來的和。

基于這樣的思路,我們可以寫出如下代碼。

參考代碼:

/////////////////////////////////////////////////////////////////////

////////

//Findthegreatestsumofallsub-arrays

//Returnvalue:iftheinputisvalid,returntrue,otherwisereturnfalse

/////////////////////////////////////////////////////////////////////

////////

boolFindGreatestSumOfSubArray

(

int*pDatar//anarray

unsignedintnLength,//thelengthofarray

int&nGreatestSum//thegreatestsumofallsub-arrays

)

(

//iftheinputisinvalid,returnfalse

if((pData==NULL)||(nLength==0))

returnfalse;

intnCurSum=nGreatestSum=0;

for(unsignedinti=0;i<nLength;++i)

{

nCurSum+=pData[i];

//ifthecurrentsumisnegative,discardit

if(nCurSum<0)

nCurSum=0;

//ifagreatersumisfound,updatethegreatestsum

if(nCurSum>nGreatestSum)

nGreatestSum=nCurSum;

}

//ifalldataarenegative,findthegreatestelementinthearray

if(nGreatestSum==0)

{

nGreatestSum=pData[0];

for(unsignedinti=1;i<nLength;++i)

{

if(pData[i]>nGreatestSum)

nGreatestSum=pData[i];

}

)

returntrue;

}

討論:上述代碼中有兩點(diǎn)值得和大家討論一下:

?函數(shù)的返回值不是子數(shù)組和的最大值,而是一個(gè)判斷輸入是否有效的標(biāo)志。如果函數(shù)返回值的是子數(shù)

組和的最大值,那么當(dāng)輸入?個(gè)空指針是應(yīng)該返回什么呢?返回0?那這個(gè)函數(shù)的用戶怎么區(qū)分輸入無效

和子數(shù)組和的最大值剛好是。這兩中情況呢?基于這個(gè)考慮,本人認(rèn)為把子數(shù)組和的最大值以引用的方式

放到參數(shù)列表中,同時(shí)讓函數(shù)返回一個(gè)函數(shù)是否正常執(zhí)行的標(biāo)志。

?輸入有一類特殊情況需要特殊處理。肖輸入數(shù)組中所有整數(shù)都是負(fù)數(shù)時(shí),子數(shù)組和的最大值就是數(shù)組

中的最大元素。

(04)一在二元樹中找出和為某一值的所有路徑

題目:輸入一個(gè)整數(shù)和一棵二元樹。從樹的根結(jié)點(diǎn)開始往下訪問一直到葉結(jié)點(diǎn)所經(jīng)過的所有結(jié)點(diǎn)形成一條

路徑。打印出和與輸入整數(shù)相等的所有路徑。

例如輸入整數(shù)22和如下二元樹

10

/\

512

/\

47

則打印出兩條路徑:10,12和10,5,7o

二元樹結(jié)點(diǎn)的數(shù)據(jù)結(jié)構(gòu)定義為:

structBinaryTreeNode//anodeinthebinarytree

(

intm_nValue;//valueofnode

BinaryTreeNode*m_pLeft;//leftchildofnode

BinaryTreeNode*m_pRight;//rightchildofnode

};

分析:這是百度的一道筆試題,考查對(duì)樹這種基本數(shù)據(jù)結(jié)構(gòu)以及遞歸函數(shù)的理解。

當(dāng)訪問到某一結(jié)點(diǎn)時(shí),把該結(jié)點(diǎn)添加到路徑上,并累加當(dāng)前結(jié)點(diǎn)的值。如果當(dāng)前結(jié)點(diǎn)為葉結(jié)點(diǎn)并且當(dāng)前路

徑的和剛好等于輸入的整數(shù),則當(dāng)前的路徑符合要求,我們把它打印出來。如果當(dāng)前結(jié)點(diǎn)不是葉結(jié)點(diǎn),則

繼續(xù)訪問它的子結(jié)點(diǎn)。當(dāng)前結(jié)點(diǎn)訪問結(jié)束后,遞歸函數(shù)將自動(dòng)回到父結(jié)點(diǎn)。因此我們在函數(shù)退出之前要在

路徑上刪除當(dāng)前結(jié)點(diǎn)并減去當(dāng)前結(jié)點(diǎn)的值,以確保返回父結(jié)點(diǎn)時(shí)路徑剛好是根結(jié)點(diǎn)到父結(jié)點(diǎn)的路徑。我們

不難看出保存路徑的數(shù)據(jù)結(jié)構(gòu)實(shí)際上是一個(gè)棧結(jié)構(gòu),因?yàn)槁窂揭c遞歸調(diào)用狀態(tài)一致,而遞歸調(diào)用本質(zhì)就

是?個(gè)壓棧和出棧的過程。

參考代碼:

/////////////////////////////////////////////////////////////////////

//

//Findpathswhosesumequaltoexpectedsum

/////////////////////////////////////////////////////////////////////

//

voidFindPath

(

BinaryTreeNode*pTreeNode,//anodeofbinarytree

intexpectedSumz//theexpectedsum

std::vector<int>&pathA//apathfromroottocurrentnode

int¤tSum//thesumofpath

)

(

if(IpTreeNode)

return;

currentSum+=pTreeNode->m_nValue;

path.push_back(pTreeNode->m_nValue);

//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<<1\t';

std::cout<<std::endl;

}

//ifthenodeisnotaleaf,gotoitschildren

if(pTreeNode->m_pLeft)

FindPath(pTreeNode->m_pLeftzexpectedSum,path,currentSum);

if(pTreeNode->m_pRight)

FindPath(pTreeNode->m__pRightzexpectedSum,path,currentSum);

//whenwefinishvisitinganodeandreturntoitsparentnode,

//weshoulddeletethisnodefromthepathand

//minusthenode1svaluefromthecurrentsum

currentSum-=pTreeNode->m_nValue;

path.pop_back();

)

(05)一查找最小的k個(gè)元素

題目:輸入n個(gè)整數(shù),輸出其中最小的k個(gè)。

例如輸入1,2,3,4,5,6,7和8這8個(gè)數(shù)字,則最小的4個(gè)數(shù)字為1,2,3和4。

分析:這道題最簡單的思路莫過于把輸入的n個(gè)整數(shù)排序,這樣排在最前面的k個(gè)數(shù)就是最小的k個(gè)數(shù)。

只是這種思路的時(shí)間復(fù)雜度為O(n頌)。我們試著尋找更快的解決思路.

我們可以開辟?個(gè)長度為k的數(shù)組。每次從輸入的n個(gè)整數(shù)中讀入?個(gè)數(shù)。如果數(shù)組中已經(jīng)插入的元素少

于k個(gè),則將讀入的整數(shù)直接放到數(shù)組中。否則長度為k的數(shù)組已經(jīng)滿了,不能再往數(shù)組里插入元素,只

能替換了。如果讀入的這個(gè)整數(shù)比數(shù)組中已有k個(gè)整數(shù)的最大值耍小,則用讀入的這個(gè)整數(shù)替換這個(gè)最大

值;如果讀入的整數(shù)比數(shù)組中已有k個(gè)整數(shù)的最大值還要大,則讀入的這個(gè)整數(shù)不可能是最小的k個(gè)整數(shù)

之、拋棄這個(gè)整數(shù)。這種思路相當(dāng)于只要排序k個(gè)整數(shù),因此時(shí)間復(fù)雜可以降到O(n+n/%k)“通?!?/p>

況卜k要遠(yuǎn)小于n,所以這種辦法要優(yōu)于前面的思路。

這是我能夠想出來的最快的解決方案。不過從給面試官留下更好印象的角度出發(fā),我們可以進(jìn)一步把代碼

寫得更漂亮一些。從上面的分析,當(dāng)長度為k的數(shù)組己經(jīng)滿了之后,如果需要替換,每次替換的都是數(shù)組

中的最大值。在常用的數(shù)據(jù)結(jié)構(gòu)中,能夠在。(1)時(shí)間里得到最大值的數(shù)據(jù)結(jié)構(gòu)為最大堆。因此我們可以用

堆(heap)來代替數(shù)組。

另外,自己重頭開始寫一個(gè)最大堆需要一定量的代碼。我們現(xiàn)在不需要重新去發(fā)明車輪,因?yàn)榍叭嗽缇桶l(fā)

明出來了。同樣,STL中的set和multiset為我們做了很好的堆的實(shí)現(xiàn),我們可以拿過來用。既偷了懶,

又給面試官留下熟悉STL的好印象,何樂而不為之?

參考代碼:

#include<set>

#include<vector>

#include<iostream>

usingnamespacestd;

typedefmultiset<intrgreater<int>>IntHeap;

/////////////////////////////////////////////////////////////////////

//

//findkleastnumbersinavector

/////////////////////////////////////////////////////////////////////

//

voidFindKLeastNumbers

(

constvector<int>&data,//avectorofdata

IntHeap&leastNumbers,//kleastnumberszoutput

unsignedintk

(

leastNumbers.clear();

if(k==0||data.size()<k)

return;

vector<int>::const_iteratoriter=data.begin();

for(;iter!=data.endO;++iter)

//iflessthanknumberswasinsertedintoleastNumbers

if((leastNumbers.size())<k)

leastNumbers.insert(*iter);

//leastNumberscontainsknumbersandit'sfullnow

else

(

//firstnumberinleastNumbersisthegreatestone

IntHeap::iteratoriterFirst=leastNumbers.begin();

//ifislessthanthepreviousgreatestnumber

if(*iter<*(leastNumbers.begin()))

(

//replacethepreviousgreatestnumber

leastNumbers.erase(iterFirst);

leastNumbers.insert(*iter);

}

}

(06)一判斷整數(shù)序列是不是二元查找樹的后序遍歷結(jié)果

題目:輸入一個(gè)整數(shù)數(shù)組,判斷該數(shù)組是不是某:元查找樹的后序遍歷的結(jié)果。如果是返回true,否則返

回false。

例如輸入5、7、6、9、11、10、8,由于這一整數(shù)序列是如下樹的后序遍歷結(jié)果:

8

/\

610

/\/\

57911

因此返回true。

如果輸入7、4、6、5,沒有哪棵樹的后序遍歷的結(jié)果是這個(gè)序列,因此返回false。

分析:這是?道trilogy的筆試題,主要考查對(duì)二元查找樹的理解。

在后續(xù)遍歷得到的序列中,最后一個(gè)元素為樹的根結(jié)點(diǎn)。從頭開始掃描這個(gè)序列,比根結(jié)點(diǎn)小的元素都應(yīng)

該位于序列的左半部分;從第一個(gè)大于跟結(jié)點(diǎn)開始到跟結(jié)點(diǎn)前面的一個(gè)元素為止,所有元素都應(yīng)該大于跟

結(jié)點(diǎn),因?yàn)檫@部分元素對(duì)應(yīng)的是樹的右子樹。根據(jù)這樣的劃分,把序列劃分為左右兩部分,我們遞歸地確

認(rèn)序列的左、右兩部分是不是都是二元查找樹。

參考代碼:

usingnamespacestd;

/////////////////////////////////////////////////////////////////////

//

//Verifywhetherasquenceofintegersarethepostordertraversal

//ofabinarysearchtree(BST)

//Input:squence-thesquenceofintegers

//length-thelengthofsquence

//Return:returntureifthesquenceistraversalresultofaBST,

//otherwise,returnfalse

/////////////////////////////////////////////////////////////////////

//

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;

)

//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);

}

(07)一翻轉(zhuǎn)句子中單詞的順序

題目:輸入一個(gè)英文句子,翻轉(zhuǎn)句子中單詞的順序,但單詞內(nèi)字符的順序不變。句子中單詞以空格符隔開。

為簡單起見,標(biāo)點(diǎn)符號(hào)和普通字母一樣處理。

例如輸入“Iamastudent.n,則輸出ustudent,aamI”。

分析:由于編寫字符串相關(guān)代碼能夠反映程序員的編程能力和編程習(xí)慣,與字符串相關(guān)的問題?直是程序

員筆試、面試題的熱門題目。本題也曾多次受到包括微軟在內(nèi)的大量公司的青睞。

由于本題需要翻轉(zhuǎn)句子,我們先顛倒句子中的所有字符。這時(shí),不但翻轉(zhuǎn)了句子中單詞的順序,而且單詞

內(nèi)字符也被翻轉(zhuǎn)了。我們再顛倒每個(gè)單詞內(nèi)的字符。由于單詞內(nèi)的字符被翻轉(zhuǎn)兩次,因此順序仍然和輸入

時(shí)的順序保持一致。

還是以上面的輸入為例子。翻轉(zhuǎn)“l(fā)amastudent.”中所有字符得到".tnedutsamal”,再翻轉(zhuǎn)每個(gè)單詞

中字符的順序得到“students,aamI",正是符合要求的輸出。

參考代碼:

/////////////////////////////////////////////////////////////////////

//

//Reverseastringbetweentwopointers

//Input:pBegin-thebeginpointerinastring

//pEnd-theendpointerinastring

/////////////////////////////////////////////////////////////////////

//

voidReverse(char*pBeginzchar*pEnd)

(

if(pBegin==NULL||pEnd==NULL)

return;

while(pBegin<pEnd)

{

chartemp=*pBegin;

*pBegin=*pEnd;

*pEnd=temp;

pBegin++,pEnd;

}

}

/////////////////////////////////////////////////////////////////////

//

//Reversethewordorderinasentence,butmaintainthecharacter

//orderinsideaword

//Input:pData-thesentencetobereversed

/////////////////////////////////////////////////////////////////////

//

char*Reversesentence(char*pData)

(

if(pData==NULL)

returnNULL;

char*pBegin=pData;

char*pEnd=pData;

while(*pEnd!=

pEnd++;

pEnd一一;

//Reversethewholesentence

Reverse(pBegin,pEnd);

//Reverseeverywordinthesentence

pBegin=pEnd=pData;

while(*pBegin!=1\0T)

{

if(*pBegin==1')

(

pBegin++;

pEnd++;

continue;

)

//AwordisbetweenwithpBeginandpEnd,reverseit

elseif(*pEnd==1'||*pEnd==1\0*)

(

Reverse(pBegin,——pEnd);

pBegin=++pEnd;

)

else

(

pEnd++;

)

)

returnpData;

(08)—求1+2+...+n

題IR:求1+2+...+n,要求不能使用乘除法、for、while、if、else、switch>case等關(guān)鍵字以及條件判斷

語句(A?B:C)o

分析:這道題沒有多少實(shí)際意義,因?yàn)樵谲浖_發(fā)中不會(huì)有這么變態(tài)的限制。但這道題卻能有效地考杳發(fā)

散思維能力,而發(fā)散思維能力能反映出對(duì)編程相關(guān)技術(shù)理解的深刻程度。

通常求1+2+…+n除了用公式n(n+1)/2之外無外乎循環(huán)和遞歸兩種思路。由于已經(jīng)明確限制for和while

的使用,循環(huán)已經(jīng)不能再用了。同樣,遞歸函數(shù)也需要用if語句或者條件判斷語句來判斷是繼續(xù)遞歸下去

還是終止遞歸,但現(xiàn)在題目已經(jīng)不允許使用這兩種語句了。

我們?nèi)匀粐@循環(huán)做文章。循環(huán)只是讓相同的代碼執(zhí)行n遍而已,我們完全可以不用for和while達(dá)到這個(gè)

效果。比如定義一個(gè)類,我們new—含有n個(gè)這種類型元素的數(shù)組,那么該類的構(gòu)造函數(shù)將確定會(huì)被調(diào)用

n次。我們可以將需要執(zhí)行的代碼放到構(gòu)造函數(shù)里。如下代碼正是基于這個(gè)思路:

classTemp

(

public:

Temp(){++N;Sum+=N;}

staticvoidReset(){N=0;Sum=0;}

staticintGetSum(){returnSum;}

private:

staticintN;

staticintSum;

};

intTemp::N=0;

intTemp::Sum=0;

intsolutionl_Sum(intn)

(

Temp::Reset();

Temp*a=newTemp[n];

delete[]a;

a=0;

returnTemp::GetSum();

}

我們同樣也可以圍繞遞歸做文章。既然不能判斷是不是應(yīng)該終止遞歸,我們不妨定義兩個(gè)函數(shù)。一個(gè)函數(shù)

充當(dāng)遞歸函數(shù)的角色,另一個(gè)函數(shù)處理終止遞歸的情況,我們需要做的就是在兩個(gè)函數(shù)里二選一。從二選

一我們很自然的想到布爾變量,比如ture(1)的時(shí)候調(diào)用第一個(gè)函數(shù),false(0)的時(shí)候調(diào)用第二個(gè)函數(shù)。

那現(xiàn)在的問題是如和把數(shù)值變量n轉(zhuǎn)換成布爾值。如果對(duì)n連續(xù)做兩次反運(yùn)算,即!!n,那么非零的n轉(zhuǎn)換

為true,0轉(zhuǎn)換為false。有了上述分析,我們再來看下面的代碼:

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);

returnvalue;

)

這種方法是用虛函數(shù)來實(shí)現(xiàn)函數(shù)的選擇。當(dāng)n不為零時(shí),執(zhí)行函數(shù)B::Su也當(dāng)n為。時(shí),執(zhí)行A::Sumo

我們也可以直接用函數(shù)指針數(shù)組,這樣可能還更直接?些:

typedefint(*fun)(int);

intsolution3_f1(inti)

(

return0;

}

intsolution3_f2(inti)

(

funf[2]={solution3_f1,solution3_f2};

returni+f[!!i](i-1);

}

另外我們還可以讓編譯器幫我們來完成類似于遞歸的運(yùn)算,比如如下代碼:

template<intn>structsolution4_Sum

(

enumValue{N=solution4_Sum<n-1>::N+n};

)i

template<>structsolution4_Sum<l>

(

enumValue{N=1};

};

solution4_Sum<100>::N就是1+2+...+100的結(jié)果。當(dāng)編譯器看到solution4_Sum<lOO>0t,

就是為模板類solution4_Sum以參數(shù)100生成該類型的代碼。但以100為參數(shù)的類型需要得到以99

為參數(shù)的類型,因?yàn)閟olution4_Sum<100>::N=solution4_Sum<99>::N+100。這個(gè)過程會(huì)

遞歸一直到參數(shù)為1的類型,由于該類型已經(jīng)顯式定義,編譯器無需生成,遞歸編譯到此結(jié)束。由于這個(gè)

過程是在編譯過程中完成的,因此要求輸入n必須是在編譯期間就能確定,不能動(dòng)態(tài)輸入。這是該方法最

大的缺點(diǎn)。而且編譯器對(duì)遞歸編譯代碼的遞歸深度是有限制的,也就是要求n不能太大。

大家還有更多、更巧妙的思路嗎?歡迎討論A_A

更好的方法:

intfunc(intn)

{

inti=1;

(n>1)&&(i=func(n-1)+n);

returni;

)

哈哈還仃個(gè)變態(tài)的辦法…就是數(shù)組溢出的異常.

privatearr=newint[n]

intadd(inti)

try{

arr[i]=i;〃當(dāng)數(shù)組溢出的時(shí)候就拋出異常

sum=i+add(i)

returnsum;

catch(exceptione)

returni;

)

(09)一查找鏈表中倒數(shù)第k個(gè)結(jié)點(diǎn)

題目:輸入一個(gè)單向鏈表,輸出該鏈表中倒數(shù)第k個(gè)結(jié)點(diǎn)。鏈表的倒數(shù)第。個(gè)結(jié)點(diǎn)為鏈表的尾指針。鏈表

結(jié)點(diǎn)定義如F:

structListNode

(

intm_nKey;

ListNode*m_pNext;

};

分析:為了得到倒數(shù)第k個(gè)結(jié)點(diǎn),很自然的想法是先走到鏈表的尾端,再從尾端回溯k步??墒禽斎氲氖?/p>

單向鏈表,只有從前往后的指針而沒有從后往前的指

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論