2023年程序員面試題精選_第1頁
2023年程序員面試題精選_第2頁
2023年程序員面試題精選_第3頁
2023年程序員面試題精選_第4頁
2023年程序員面試題精選_第5頁
已閱讀5頁,還剩8頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

程序員面試題精選100題(10)-在排序數(shù)組中查找和為給定值的兩個數(shù)字HYPERLINK""\l"m=0&t=1&c=fks_"數(shù)組2023-03-1415:25:01閱讀4663評論15

字號:大中小

訂閱題目:輸入一個已經(jīng)按升序排序過的數(shù)組和一個數(shù)字,在數(shù)組中查找兩個數(shù),使得它們的和正好是輸入的那個數(shù)字。規(guī)定期間復(fù)雜度是O(n)。假如有多對數(shù)字的和等于輸入的數(shù)字,輸出任意一對即可。例如輸入數(shù)組1、2、4、7、11、15和數(shù)字15。由于4+11=15,因此輸出4和11。分析:假如我們不考慮時間復(fù)雜度,最簡樸想法的莫過去先在數(shù)組中固定一個數(shù)字,再依次判斷數(shù)組中剩下的n-1個數(shù)字與它的和是不是等于輸入的數(shù)字??上н@種思緒需要的時間復(fù)雜度是O(n2)。我們假設(shè)現(xiàn)在隨便在數(shù)組中找到兩個數(shù)。假如它們的和等于輸入的數(shù)字,那太好了,我們找到了要找的兩個數(shù)字;假如小于輸入的數(shù)字呢?我們希望兩個數(shù)字的和再大一點。由于數(shù)組已經(jīng)排好序了,我們是不是可以把較小的數(shù)字的往后面移動一個數(shù)字?由于排在后面的數(shù)字要大一些,那么兩個數(shù)字的和也要大一些,就有也許等于輸入的數(shù)字了;同樣,當(dāng)兩個數(shù)字的和大于輸入的數(shù)字的時候,我們把較大的數(shù)字往前移動,由于排在數(shù)組前面的數(shù)字要小一些,它們的和就有也許等于輸入的數(shù)字了。我們把前面的思緒整理一下:最初我們找到數(shù)組的第一個數(shù)字和最后一個數(shù)字。當(dāng)兩個數(shù)字的和大于輸入的數(shù)字時,把較大的數(shù)字往前移動;當(dāng)兩個數(shù)字的和小于數(shù)字時,把較小的數(shù)字往后移動;當(dāng)相等時,打完收工。這樣掃描的順序是從數(shù)組的兩端向數(shù)組的中間掃描。問題是這樣的思緒是不是對的的呢?這需要嚴(yán)格的數(shù)學(xué)證明。感愛好的讀者可以自行證明一下。參考代碼:///////////////////////////////////////////////////////////////////////?//Findtwonumberswithasuminasortedarray?//Output:tureisfoundsuchtwonumbers,otherwisefalse

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

boolFindTwoNumbersWithSum

(

?intdata[],//asortedarray

?unsignedintlength,//thelengthofthesortedarray?

intsum,//thesum? int&num1,//thefirstnumber,output

?int&num2//thesecondnumber,output

)?{?boolfound=false;??if(length<1)? returnfound;

?intahead=length-1;? intbehind=0;???while(ahead>behind)

?{? ?longlongcurSum=data[ahead]+data[behind];

//ifthesumoftwonumbersisequaltotheinput?? //wehavefoundthem???if(curSum==sum)

?{? ? num1=dat(yī)a[behind];?? num2=data[ahead];????found=true;? ?break;

??}???//ifthesumoftwonumbersisgreaterthantheinput

? //decreasethegreaternumber? elseif(curSum>sum)

ahead--;

??//ifthesumoftwonumbersislessthantheinput? ?//increasethelessnumber

?else

behind++;

?}

?returnfound;?}擴(kuò)展:假如輸入的數(shù)組是沒有排序的,但知道里面數(shù)字的范圍,其他條件不變,如何在O(n)時間里找到這兩個數(shù)字程序員面試題精選100題(11)-求二元查找樹的鏡像HYPERLINK""\l"m=0&t=1&c=fks_"樹2023-03-1509:36:33閱讀3906評論9

字號:大中小

訂閱題目:輸入一顆二元查找樹,將該樹轉(zhuǎn)換為它的鏡像,即在轉(zhuǎn)換后的二元查找樹中,左子樹的結(jié)點都大于右子樹的結(jié)點。用遞歸和循環(huán)兩種方法完畢樹的鏡像轉(zhuǎn)換。例如輸入:8?/\?610?

/\/\

57911輸出:8?/\

106?

/\

/\

119

75定義二元查找樹的結(jié)點為:structBSTreeNode//anodeinthebinarysearchtree(BST)?{? intm_nValue;//valueofnode

?BSTreeNode*m_pLeft;//leftchildofnode??BSTreeNode*m_pRight;//rightchildofnode?};分析:盡管我們也許一下子不能理解鏡像是什么意思,但上面的例子給我們的直觀感覺,就是互換結(jié)點的左右子樹。我們試著在遍歷例子中的二元查找樹的同時來互換每個結(jié)點的左右子樹。遍歷時一方面訪問頭結(jié)點8,我們互換它的左右子樹得到:8?/\?106?

/\/\?91157我們發(fā)現(xiàn)兩個結(jié)點6和10的左右子樹仍然是左結(jié)點的值小于右結(jié)點的值,我們再試著互換他們的左右子樹,得到:8?/\?106?

/\

/\?119

75剛好就是規(guī)定的輸出。上面的分析印證了我們的直覺:在遍歷二元查找樹時每訪問到一個結(jié)點,互換它的左右子樹。這種思緒用遞歸不難實現(xiàn),將遍歷二元查找樹的代碼稍作修改就可以了。參考代碼如下:///////////////////////////////////////////////////////////////////////?//MirroraBST(swaptheleftrightchildofeachnode)recursively

//theheadofBSTininitialcall

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

voidMirrorRecursively(BSTreeNode*pNode)

{??if(!pNode)???return;

//swaptherightandleftchildsub-tree??BSTreeNode*pTemp=pNode->m_pLeft;??pNode->m_pLeft=pNode->m_pRight;? pNode->m_pRight=pTemp;???//mirrorleftchildsub-treeifnotnull? if(pNode->m_pLeft)

MirrorRecursively(pNode->m_pLeft);

??//mirrorrightchildsub-treeifnotnull

?if(pNode->m_pRight)?? MirrorRecursively(pNode->m_pRight);?}由于遞歸的本質(zhì)是編譯器生成了一個函數(shù)調(diào)用的棧,因此用循環(huán)來完畢同樣任務(wù)時最簡樸的辦法就是用一個輔助棧來模擬遞歸。一方面我們把樹的頭結(jié)點放入棧中。在循環(huán)中,只要棧不為空,彈出棧的棧頂結(jié)點,互換它的左右子樹。假如它有左子樹,把它的左子樹壓入棧中;假如它有右子樹,把它的右子樹壓入棧中。這樣在下次循環(huán)中就能互換它兒子結(jié)點的左右子樹了。參考代碼如下:///////////////////////////////////////////////////////////////////////?//MirroraBST(swaptheleftrightchildofeachnode)Iterat(yī)ively?//Input:pTreeHead:theheadofBST

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

voidMirrorIteratively(BSTreeNode*pTreeHead)?{? if(?。餞reeHead)???return;

std::stack<BSTreeNode*>stackTreeNode;??stackTreeNode.push(pTreeHead);??while(stackTreeNode.size())??{? ?BSTreeNode*pNode=stackTreeNode.top();? ?stackTreeNode.pop();?? ?//swaptherightandleftchildsub-tree? ?BSTreeNode*pTemp=pNode->m_pLeft;

pNode->m_pLeft=pNode->m_pRight;?? pNode->m_pRight=pTemp;?

? //pushleftchildsub-treeintostackifnotnull? if(pNode->m_pLeft)

? ?stackTreeNode.push(pNode->m_pLeft);

??//pushrightchildsub-treeintostackifnotnull

? if(pNode->m_pRight)

? stackTreeNode.push(pNode->m_pRight);??}

}程序員面試題精選100題(12)-從上往下遍歷二元樹HYPERLINK""\l"m=0&t=1&c=fks_"隊列2023-03-1921:17:03閱讀3798評論5

字號:大中小

訂閱

題目:輸入一顆二元樹,從上往下按層打印樹的每個結(jié)點,同一層中按照從左往右的順序打印。例如輸入8

/\?610?

/\/\

57911輸出861057911。分析:這曾是微軟的一道面試題。這道題實質(zhì)上是規(guī)定遍歷一棵二元樹,只但是不是我們熟悉的前序、中序或者后序遍歷。我們從樹的根結(jié)點開始分析。自然先應(yīng)當(dāng)打印根結(jié)點8,同時為了下次可以打印8的兩個子結(jié)點,我們應(yīng)當(dāng)在遍歷到8時把子結(jié)點6和10保存到一個數(shù)據(jù)容器中?,F(xiàn)在數(shù)據(jù)容器中就有兩個元素6

和10了。按照從左往右的規(guī)定,我們先取出6訪問。打印6的同時要把6的兩個子結(jié)點5和7放入數(shù)據(jù)容器中,此時數(shù)據(jù)容器中有三個元素10、5和7。接下來我們應(yīng)當(dāng)從數(shù)據(jù)容器中取出結(jié)點10訪問了。注意10比5和7先放入容器,此時又比5和7先取出,就是我們通常說的先入先出。因此不難看出這個數(shù)據(jù)容器的類型應(yīng)當(dāng)是個隊列。既然已經(jīng)擬定數(shù)據(jù)容器是一個隊列,現(xiàn)在的問題變成怎么實現(xiàn)隊列了。事實上我們無需自己動手實現(xiàn)一個,由于STL已經(jīng)為我們實現(xiàn)了一個很好的deque(兩端都可以進(jìn)出的隊列),我們只需要拿過來用就可以了。我們知道樹是圖的一種特殊退化形式。同時假如對圖的深度優(yōu)先遍歷和廣度優(yōu)先遍歷有比較深刻的理解,將不難看出這種遍歷方式事實上是一種廣度優(yōu)先遍歷。因此這道題的本質(zhì)是在二元樹上實現(xiàn)廣度優(yōu)先遍歷。參考代碼:#include<deque>

#include<iostream>

usingnamespacestd;?structBTreeNode//anodeinthebinarytree

{

intm_nValue;//valueofnode

BTreeNode*m_pLeft;//leftchildofnode

?BTreeNode*m_pRight;//rightchildofnode

};

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

//Printabinarytreefromtopleveltobottomlevel?//Input:pTreeRoot-therootofbinarytree

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

voidPrintFromTopToBottom(BTreeNode*pTreeRoot)?{

?if(!pTreeRoot)

? return;?? //getaemptyqueue? deque<BTreeNode*>dequeTreeNode;

??//inserttherootat(yī)thetailofqueue

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);??}?}程序員面試題精選100題(13)-第一個只出現(xiàn)一次的字符HYPERLINK""\l"m=0&t=1&c=fks_"雜題2023-03-2512:03:22閱讀4450評論8

字號:大中小

訂閱題目:n個數(shù)字(0,1,…,n-1)形成一個圓圈,從數(shù)字0開始,每次從這個圓圈中刪除第m個數(shù)字(第一個為當(dāng)前數(shù)字自身,第二個為當(dāng)前數(shù)字的下一個數(shù)字)。當(dāng)一個數(shù)字刪除后,從被刪除數(shù)字的下一個繼續(xù)刪除第m個數(shù)字。求出在這個圓圈中剩下的最后一個數(shù)字。分析:既然題目有一個數(shù)字圓圈,很自然的想法是我們用一個數(shù)據(jù)結(jié)構(gòu)來模擬這個圓圈。在常用的數(shù)據(jù)結(jié)構(gòu)中,我們很容易想到用環(huán)形列表。我們可以創(chuàng)建一個總共有m個數(shù)字的環(huán)形列表,然后每次從這個列表中刪除第m個元素。在參考代碼中,我們用STL中std::list來模擬這個環(huán)形列表。由于list并不是一個環(huán)形的結(jié)構(gòu),因此每次跌代器掃描到列表末尾的時候,要記得把跌代器移到列表的頭部。這樣就是按照一個圓圈的順序來遍歷這個列表了。這種思緒需要一個有n個結(jié)點的環(huán)形列表來模擬這個刪除的過程,因此內(nèi)存開銷為O(n)。并且這種方法每刪除一個數(shù)字需要m步運算,總共有n個數(shù)字,因此總的時間復(fù)雜度是O(mn)。當(dāng)m和n都很大的時候,這種方法是很慢的。接下來我們試著從數(shù)學(xué)上分析出一些規(guī)律。一方面定義最初的n個數(shù)字(0,1,…,n-1)中最后剩下的數(shù)字是關(guān)于n和m的方程為f(n,m)。在這n個數(shù)字中,第一個被刪除的數(shù)字是m%n-1,為簡樸起見記為k。那么刪除k之后的剩下n-1的數(shù)字為0,1,…,k-1,k+1,…,n-1,并且下一個開始計數(shù)的數(shù)字是k+1。相稱于在剩下的序列中,k+1排到最前面,從而形成序列k+1,…,n-1,0,…k-1。該序列最后剩下的數(shù)字也應(yīng)當(dāng)是關(guān)于n和m的函數(shù)。由于這個序列的規(guī)律和前面最初的序列不同樣(最初的序列是從0開始的連續(xù)序列),因此該函數(shù)不同于前面函數(shù),記為f’(n-1,m)。最初序列最后剩下的數(shù)字f(n,m)一定是剩下序列的最后剩下數(shù)字f’(n-1,m),所以f(n,m)=f’(n-1,m)。接下來我們把剩下的的這n-1個數(shù)字的序列k+1,…,n-1,0,…k-1作一個映射,映射的結(jié)果是形成一個從0到n-2的序列:k+1->0

k+2->1?…

n-1->n-k-2

0->n-k-1

k-1->n-2把映射定義為p,則p(x)=(x-k-1)%n,即假如映射前的數(shù)字是x,則映射后的數(shù)字是(x-k-1)%n。相應(yīng)的逆映射是p-1(x)=(x+k+1)%n。由于映射之后的序列和最初的序列有同樣的形式,都是從0開始的連續(xù)序列,因此仍然可以用函數(shù)f來表達(dá),記為f(n-1,m)。根據(jù)我們的映射規(guī)則,映射之前的序列最后剩下的數(shù)字f’(n-1,m)=p-1[f(n-1,m)]=[f(n-1,m)+k+1]%n。把k=m%n-1代入得到f(n,m)=f’(n-1,m)=[f(n-1,m)+m]%n。通過上面復(fù)雜的分析,我們終于找到一個遞歸的公式。要得到n個數(shù)字的序列的最后剩下的數(shù)字,只需要得到n-1個數(shù)字的序列的最后剩下的數(shù)字,并可以依此類推。當(dāng)n=1時,也就是序列中開始只有一個數(shù)字0,那么很顯然最后剩下的數(shù)字就是0。我們把這種關(guān)系表達(dá)為:0n=1?f(n,m)={?[f(n-1,m)+m]%nn>1盡管得到這個公式的分析過程非常復(fù)雜,但它用遞歸或者循環(huán)都很容易實現(xiàn)。最重要的是,這是一種時間復(fù)雜度為O(n),空間復(fù)雜度為O(1)的方法,因此無論在時間上還是空間上都優(yōu)于前面的思緒。思緒一的參考代碼:///////////////////////////////////////////////////////////////////////

//nintegers(0,1,...n-1)formacircle.Removethemthfrom

//thecircleateverytime.Findthelastnumberremaining

//Input:n-thenumberofintegersinthecircleinitially?//m-removethemthnumberateverytime?//Output:thelastnumberremainingwhentheinputisvalid,

//otherwise-1

///////////////////////////////////////////////////////////////////////?intLastRemaining_Solution1(unsignedintn,unsignedintm)

{??//invalidinput

?if(n<1||m<1)? return-1;

unsignedinti=0;?? //initiatealistwithnintegers(0,1,...n-1)

list<int>integers;

for(i=0;i<n;++i)?? integers.push_back(i);?

?list<int>::iterat(yī)orcurinteger=integers.begin();

?while(integers.size()>1)? {? //findthemthinteger.Notethatstd::listisnotacircle?? //soweshouldhandleitmanually

??for(inti=1;i<m;++i)???{

? curinteger++;

? ?if(curinteger==integers.end())? ? curinteger=integers.begin();

}?? //removethemthinteger.Notethatstd::listisnotacircle? //sowesh

溫馨提示

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

評論

0/150

提交評論