版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
Python程序員面試分類真題111.
給定一個大小為N×N的迷宮,一只老鼠需要從迷宮的左上角(對應(yīng)矩陣的[0][0])走到迷宮的右下角(對應(yīng)矩陣的[N-1][N-1]),老鼠只能向兩方向移動:向右或向下。(江南博哥)在迷宮中,0表示沒有路(是死胡同),1表示有路。例如:給定下面的迷宮:
圖中標粗的路徑就是一條合理的路徑。請給出算法來找到這么一條合理路徑。正確答案:最容易想到的方法就是嘗試所有可能的路徑,找出可達的一條路。顯然這種方法效率非常低下,這里重點介紹一種效率更高的回溯法。主要思路為:當(dāng)碰到死胡同的時候,回溯到前一步,然后從前一步出發(fā)繼續(xù)尋找可達的路徑。算法的主要框架為:申請一個結(jié)果矩陣來標記移動的路徑if到達了目的地打印解決方案矩陣else(1)在結(jié)果矩陣中標記當(dāng)前為1(1表示移動的路徑)。(2)向右前進一步,然后遞歸地檢查,走完這一步后,判斷是否存在到終點的可達的路線。(3)如果步驟(2)中的移動方法導(dǎo)致沒有通往終點的路徑,那么選擇向下移動一步,然后檢查使用這種移動方法后,是否存在到終點的可達的路線。(4)如果上面的移動方法都會導(dǎo)致沒有可達的路徑,那么標記當(dāng)前單元格在結(jié)果矩陣中為0,返回false,并回溯到前一步中。
根據(jù)以上框架很容易進行代碼實現(xiàn)。示例代碼如下:
classMaze:
def__init__(self):
self.N=4
#打印從起點到終點的路線
defprintSolution(self,sol):
i=0
whilei<self.N:
j=0
whilej<self.N:
printsol[i][j],
j+=1
print'\n'
i+=1
#判斷x和y是否是一個合理的單元
defisSafe(self,maze,x,y):
returnx>=0andx<self.Nandy>=0and\
y<self.Nandmaze[x][y]==1
"""
使用回溯的方法找到一條從左上角到右下角的路徑
maze表示迷宮,x、y表示起點,sol存儲結(jié)果
"""
defgetPath(self,maze,x,y,sol):
#到達目的地
ifx==self.N-1andy==self.N-1:
sol[x][y]=1
returnTrue
#判斷maze[x][y]是否是一個可走的單元
ifself.isSafe(maze,x,y):
#標記當(dāng)前單元為1
sol[x][y]=1
#向右走一步
ifself.getPath(maze,x+1,y,sol):
returnTrue
#向下走一步
ifself.getPath(maze,x,y+1,sol):
returnTrue
#標記當(dāng)前單元為0用來表示這條路不可行,然后回溯
sol[x][y]=0
returnFalse
returnFalse
if__name__=="__main__":
rat=Maze()
maze=[[1,0,0,0],
[1,1,0,1],
[0,1,0,0],
[1,1,1,1]]
sol=[[0,0,0,0],
[0,0,0,0],
[0,0,0,0],
[0,0,0,0]]
ifnotrat.getPath(maze,0,0,sol):
print"不存在可達的路徑"
else:
rat.printSolution(sol)
程序的運行結(jié)果為:
1000
1100
0100
0111[考點]如何求解迷宮問題
2.
給定以非遞減順序排序的三個數(shù)組,找出這三個數(shù)組中的所有公共元素。例如,給出下面三個數(shù)組:ar1=[2,5,12,20,45,85],ar2=[16,19,20,85,200],ar3=[3,4,15,20,39,72,85,190]。那么這三個數(shù)組的公共元素為[20,85]。正確答案:最容易想到的方法是首先找出兩個數(shù)組的交集,然后再把這個交集存儲在一個臨時數(shù)組中,最后再找出這個臨時數(shù)組與第三個數(shù)組的交集。這種方法的時間復(fù)雜度為O(N1+N2+N3),其中N1、N2和N3分別為三個數(shù)組的大小。這種方法不僅需要額外的存儲空間,而且還需要額外的兩次循環(huán)遍歷。下面介紹另外一種只需要一次循環(huán)遍歷、而且不需要額外存儲空間的方法,主要思路為:
假設(shè)當(dāng)前遍歷的三個數(shù)組的元素分別為ar1[i]、ar2[j]、ar3[k],則存在以下幾種可能性:
(1)如果ar1[i]、ar2[j]和ar3[k]相等,則說明當(dāng)前遍歷的元素是三個數(shù)組的公共元素,可以直接打印出來,然后通過執(zhí)行i+,j+,k+,使三個數(shù)組同時向后移動,此時繼續(xù)遍歷各數(shù)組后面的元素。
(2)如果ar1[i]<ar2[j],則執(zhí)行i+來繼續(xù)遍歷ar1中后面的元素,因為ar1[i]不可能是三個數(shù)組公共的元素。
(3)如果ar2[j]<ar3[k],同理可以通過j+來繼續(xù)遍歷ar2后面的元素。
(4)如果前面的條件都不滿足,說明ar1[i]>ar2[j]而且ar2[j]>ar3[k],此時可以通過k+來繼續(xù)遍歷ar3后面的元素。
實現(xiàn)代碼如下:
deffindCommon(ar1,ar2,ar3):
i=0
j=0
k=0
n1=len(ar1)
n2=len(ar2)
n3=len(ar3)
#遍歷三個數(shù)組
whilei<n1andj<n2andk<n3:
#找到了公共元素
ifar1[i]==ar2[j]andar2[j]==ar3[k]:
printar1[i],
i+=1
j+=1
k+=1
#ar[i]不可能是公共元素
elifar1[i]<ar2[j]:
i+=1
#ar2[j]不可能是公共元素
elifar2[j]<ar3[k]:
j+=1
#ar3[k]不可能是公共元素
else:
k+=1
if__name__=="__main__":
ar1=[2,5,12,20,45,85]
ar2=[16,19,20,85,200]
ar3=[3,4,15,20,39,72,85,190]
fidCommon(ar1,ar2,ar3)
程序的運行結(jié)果為:
2085
算法性能分析:
這種方法的時間復(fù)雜度為O(N1+N2+N3)。[考點]如何從三個有序數(shù)組中找出它們的公共元素
3.
有兩個有序的集合,集合中的每個元素都是一段范圍,求其交集,例如集合{[4,8],[9,13]}和{[6,12]}的交集為{[6,8],[9,12]}。正確答案:方法一:蠻力法
最簡單的方法就是遍歷兩個集合,針對集合中的每個元素判斷是否有交集,如果有,則求出它們的交集,實現(xiàn)代碼如下:
classMySet:
def__init__(self,mins,maxs):
self.mins=mins
self.maxs=maxs
defgetMin(self):
returnself.mins
defsetMin(self,mins):
self.mins=mins
defgetMax(self):
returnself.maxs
defsetMax(self,maxs):
self.maxs=maxs
defgetlntersection(s1,s2):
ifs1.getMin()<s2.getMin():
ifs1.getMax()<s2.getMin():
returnNone
elifs1.getMax()<=s2.getMax():
returnMySet(s2.getMin(),s1.getMax())
else:
returnMySet(s2.getMin(),s2.getMax())
elifs1.getMin()<=s2.getMax():
ifs1.getMax()<=s2.getMax():
returnMySet(s1.getMin(),s1.getMax())
else:
returnMySet(s1.getMinO,s2.getMax())
else:
returnNone
defgetlntersection2(11,12):
result=[]
i=0
whilei<len(11):
j=0
whilej<len(12):
s=getIntersection(11[i,12[j])
ifs!=None:
result.append(s)
j+=1
i+=1
returnresult
if__name__="__main__":
11=[]
12=[]
11.append(MySet(4,8))
11.append(MySet(9,13))
12.append(MySet(6,12))
result=getIntersection2(11,12)
i=0
whilei<len(result):
print"["+str(result[i].getMin())+","+str(result[i].getMax())+"]"
i+=1
代碼運行結(jié)果為:
[6,8]
[9,12]
算法性能分析:
這種方法的時間復(fù)雜度為O(n2)。
方法二:特征法
上述這種方法顯然沒有用到集合有序的特點,因此,它不是最佳的方法。假設(shè)兩個集合為s1,s2。當(dāng)前比較的集合為s1[i]和s2[j],其中,i與j分別表示的是集合s1與s2的下標。可以分為如下幾種情況:
1)s1集合的下界小于s2的上界,如下圖所示:
在這種情況下,s1[i]和s2[j]顯然沒有交集,那么接下來只有s1[i+1]與s2[j]才有可能會有交集。
2)s1的上界介于s2的下界與上界之間,如下圖所示:
在這種情況下,s1[i]和s2[j]有交集(s2[j]的下界和s1[i]的上界),那么接下來只有s1[i+1]與s2[j]才有可能會有交集。
3)s1包含s2,如下圖所示:
在這種情況下,s1[i]和s2[j]有交集(交集為s2[j]),那么接下來只有s1[i]與s2[j+1]才有可能會有交集。
4)s2包含s1,如下圖所示:
在這種情況下,s1[i]和s2[j]有交集(交集為s1[i]),那么接下來只有s1[i+1]與s2[j]才有可能會有交集。
5)s1的下界介于s2的下界與上界之間,如下圖所示:
在這種情況下,s1[i]和s2[j]有交集(交集為s1[i]的下界和s2[j]的上界),那么接下來只有s1[i]與s2[j+1]才有可能會有交集。
6)s2的上界小于s1的下界,如下圖所示:
在這種情況下,s1[i]和s2[j]顯然沒有交集,那么接下來只有s1[i]與s2[j+1]才有可能會有交集。
根據(jù)以上分析給出實現(xiàn)代碼如下:
classMySet:
def__init__(self,mins,maxs):
self.mins=mins
self.maxs=maxs
defgetMin(self):
returnself.mins
defsetMin(self,mins):
self.mins=mins
defgetMax(self):
returnself.maxs
defsetMax(self,maxs):
self.maxs=maxs
defgetlntersection(11,12):
result=[]
i=0
j=0
whilei<len(11)andj<len(12):
s1=11[i]
s2=12[j]
ifs1.getMin()<s2.getMin():
ifs1.getMax()<s2.getMin():
i+=1
elifs1.getMax()<=s2.getMax():
result.append(MySet(s2.getMin(),s1.getMax(()))
i+=1
else:
result.append(MySet(s2.getMin(),s2.getMax()))
j+=1
elifs1.getMin()<=s2.getMax():
ifs1.getMax()<=s2.getMax():
result.append(MySet(s1.getMin(),s1.getMax()))
i+=1
else:
result.append(MySet(s1.getMin(),s2.getMax()))
j+=1
else:
j+=1
returnresult
if__name__="__main__":
11=[]
12=[]
11.append(MySet(4,8))
11.append(MySet(9,13))
12.append(MySet(6,12))
result=getIntersection(11,12)
i=0
whilei<len(result):
print"["+str(result[i].getMin())+","+str(result[i].getMax())+"]"
i+=1
算法性能分析:
這種方法的時間復(fù)雜度為O(N1+N2),其中N1、N2分別為兩個集合的大小。[考點]如何求兩個有序集合的交集
4.
給定一個數(shù)組,已知這個數(shù)組中有大量的重復(fù)的數(shù)字,如何對這個數(shù)組進行高效地排序?正確答案:如果使用常規(guī)的排序方法,雖然最好的排序算法的時間復(fù)雜度為O(NlOg2N),但是使用常規(guī)排序算法顯然沒有用到數(shù)組中有大量重復(fù)數(shù)字這個特性。如何能使用這個特性呢?下面介紹兩種更加高效的算法。
方法一:AVL樹
這種方法的主要思路為:根據(jù)數(shù)組中的數(shù)構(gòu)建一個AVL樹,這里需要對AVL樹做適當(dāng)?shù)臄U展,在結(jié)點中增加一個額外的數(shù)據(jù)域來記錄這個數(shù)字出現(xiàn)的次數(shù),在AVL樹構(gòu)建完成后,可以對AVL樹進行中序遍歷,根據(jù)每個結(jié)點對應(yīng)數(shù)字出現(xiàn)的次數(shù),把遍歷結(jié)果放回到數(shù)組中就完成了排序,實現(xiàn)代碼如下:
#AVL樹的結(jié)點
classNode:
def__init__(self,data):
self.data=data
self.left=self.right=None
self.height=self.count=1
classSort:
#中序遍歷AVL樹,把遍歷結(jié)果放入到數(shù)組中
definorder(self,arr,root,index):
ifroot!=None:
#中序遍歷左子樹
index=self.inorder(arr,root.left,index)
#把root結(jié)點對應(yīng)的數(shù)字根據(jù)出現(xiàn)的次數(shù)放入到數(shù)組中
i=0
whilei<root.count:
arr[index]=root.data
index+=1
i+=1
#中序遍歷右子樹
index=self.inorder(arr,root.right,index)
returnindex
#得到樹的高度
defgetHeight(self,node):
ifnode==None:
return0
else:
returnnode.height
#把以y為根的子樹向右旋轉(zhuǎn)
defrightRotate(self,y):
x=y.left
T2=x.right
#旋轉(zhuǎn)
x.right=y
y.left=T2
y.height=max(self.getHeight(y.left),self.getHeight(y.right))+1
x.height=max(self.getHeight(x.left),self.getHeight(x.right))+1
#返回新的根結(jié)點
returnx
#把以x為根的子樹向右旋轉(zhuǎn)
defleftRotate(self,x):
y=x.right
T2=y.left
y.left=x
x.right=T2
x.height=max(self.getHeight(x.left),self.getHeight(x.right))+1
y.height=max(self.getHeight(y.left),self.getHeight(y.right))+1
#Returnnewroot
returny
#獲取樹的平衡因子
defgetBalance(self,N):
if(N==None):
return0
returnself.getHeight(N.left)-self.getHeight(N.right)
"""
如果data在AVL樹中不存在,則把data插入到AVL樹中,否則把這個結(jié)點對應(yīng)的count加1即可
"""
definsert(self,root,data):
ifroot==None:
return(Node(data))
#data在樹中存在,把對應(yīng)的結(jié)點的count加1
ifdata==root.data:
root.count+=1
returnroot
#在左子樹中繼續(xù)查找data是否存在
ifdata<root.data:
root.left=self.insert(root.left,data)
#在右子樹中繼續(xù)查找data是否存在
else:
root.right=self.insert(root.right,data)
#插入新的結(jié)點后更新root結(jié)點的高度
root.height=max(self.getHeight(root.left),self.getHeight(root.right))+1
#獲取樹的平衡因子
balance=self.getBalance(root)
#如果樹不平衡,根據(jù)數(shù)據(jù)結(jié)構(gòu)中學(xué)過的四種情況進行調(diào)整
#LL型
ifbalance>1anddata<root.left.data:
returnself.rightRotate(root)
#RR型
elifbalance<-1anddata>root.right.data:
returnself.leftRotate(root)
#LR型
elifbalance>1anddata>root.left.data:
root.left=self.leftRotate(root.left)
returnself.rightRotate(root)
#RL型
elifbalance<-1anddata<root.right.data:
root.right=self.rightRotate(root.right)
returnself.leftRotate(root)
returnroot
#使用AVL樹實現(xiàn)排序
defsort(self,arr):
root=None#根結(jié)點
n=len(arr)
i=0
whilei<n:
root=self.insert(root,arr[i])
i+=1
index=0
self.inorder(arr,root,index)
if__name__="__main__":
arr=[15,12,15,2,2,12,2,3,12,100,3,3]
s=Sort()
s.sort(arr)
whilei<len(arr):
printarr[i],
i+=1
代碼運行結(jié)果為:
2223331212121515100
算法性能分析:
這種方法的時間復(fù)雜度為O(NLog2M),其中,N為數(shù)組的大小,M為數(shù)組中不同數(shù)字的個數(shù),空間復(fù)雜度為O(N)。
方法二:哈希法
這種方法的主要思路為創(chuàng)建一個哈希表,然后遍歷數(shù)組,把數(shù)組中的數(shù)字放入哈希表中,在遍歷的過程中,如果這個數(shù)在哈希表中存在,則直接把哈希表中這個key對應(yīng)的value加1;如果這個數(shù)在哈希表中不存在,則直接把這個數(shù)添加到哈希表中,并且初始化這個key對應(yīng)的value為1。實現(xiàn)代碼如下:
defsort(arr):
data_count=dict()
n=len(arr)
#把數(shù)組中的數(shù)放入map中
i=0
whilei<n:
ifstr(arr[i])indata_count:
data_count[str(arr[i])]=data_count.get(str(arr[i]))+1
else:
data_count[str(arr[i])]=1
i+=1
index=0
forkey,valueindata_count.items():
i=value
whilei>0:
arr[index]=key
index+=1
i-=1
if__name__="__main__":
arr=[15,12,15,2,2,12,2,3,12,100,3,3]
sort(arr)
i=0
whilei<len(arr):
printarr[i],
i+=1
算法性能分析:
這種方法的時間復(fù)雜度為O(N+MLog2M),空間復(fù)雜度為O(M)。[考點]如何對有大量重復(fù)的數(shù)字的數(shù)組排序
5.
假設(shè)有一個中央調(diào)度機,有n個相同的任務(wù)需要調(diào)度到m臺服務(wù)器上去執(zhí)行,由于每臺服務(wù)器的配置不一樣,因此,服務(wù)器執(zhí)行一個任務(wù)所花費的時間也不同?,F(xiàn)在假設(shè)第i個服務(wù)器執(zhí)行一個任務(wù)所花費的時間也不同。現(xiàn)在假設(shè)第i個服務(wù)器執(zhí)行一個任務(wù)需要的時間為t[i]。例如:有2個執(zhí)行機a與b,執(zhí)行一個任務(wù)分別需要7min,10min,有6個任務(wù)待調(diào)度。如果平分這6個任務(wù),即a與b各3個任務(wù),則最短需要30min執(zhí)行完所有。如果a分4個任務(wù),b分2個任務(wù),則最短28min執(zhí)行完。請設(shè)計調(diào)度算法,使得所有任務(wù)完成所需要的時間最短。輸入m臺服務(wù)器,每臺機器處理一個任務(wù)的時間為t[i],完成n個任務(wù),輸出n個任務(wù)在m臺服務(wù)器的分布:estimate_process_time(t,m,n)。正確答案:本題可以采用貪心法來解決,具體實現(xiàn)思路如下:
申請一個數(shù)組來記錄每臺機器的執(zhí)行時間,初始化為0,在調(diào)度任務(wù)的時候,對于每個任務(wù),在選取機器的時候采用如下的貪心策略:對于每臺機器,計算機器已經(jīng)分配任務(wù)的執(zhí)行時間+這個任務(wù)需要的時間,選用最短時間的機器進行處理。實現(xiàn)代碼如下:
"""
paramt每個服務(wù)器處理的時間
paramn任務(wù)的個數(shù)
return各個服務(wù)器執(zhí)行完任務(wù)所需的時間
"""
defcalculate_rocess_time(t,n):
ift==Noneorn<=0:
returnNone
m=len(t)
proTime=[0]*m
i=0
whilei<n:
minTime=proTime[0]+t[0]#把任務(wù)給第j個機器上后這個機器的執(zhí)行時間
minIndex=0#把任務(wù)給第minIndex個機器上
j=1
whilej<m:
#分配到第j臺機器上后執(zhí)行時間更短
ifminTime>proTime[j]+t[j]:
minTime=proTime[j]+t[j]
minIndex=j
j+=1
proTime[minIndex]+=t[minIndex]
i+=1
returnproTime
if__name__=="__main__":
t=[7,10]
n=6
proTime=calculate_process_time(t,n)
ifproTime==None:
print"分配失敗"
else:
totalTime=proTime[0]
i=0
whilei<len(proTime):
print"第"+str((i+1))+"臺服務(wù)器有"+str(proTime[i]/t[i])+"個任務(wù),執(zhí)行總時間為:"+str(proTim
溫馨提示
- 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 高風(fēng)險區(qū)域消防安全方案
- 預(yù)制構(gòu)件安裝技術(shù)方案
- 建筑工程綠化施工方案
- 農(nóng)田有機農(nóng)業(yè)發(fā)展推廣方案
- 道路交通流量預(yù)測模型方案
- 消防設(shè)施維保管理方案
- 熱力系統(tǒng)供水水質(zhì)保障方案
- 公路施工人員健康管理方案
- 2026年金融衍生品解析期權(quán)定價原理題目
- 2026年注冊會計師CPA稅法部分模擬題
- 2025年《物聯(lián)網(wǎng)工程設(shè)計與管理》課程標準
- T-CSTM 00394-2022 船用耐火型氣凝膠復(fù)合絕熱制品
- 滬教版6年級上冊數(shù)學(xué)提高必刷題(有難度) (解析)
- DBJ50-T-086-2016重慶市城市橋梁工程施工質(zhì)量驗收規(guī)范
- 固態(tài)電池及固態(tài)電池的制造方法培訓(xùn)課件
- 川農(nóng)畢業(yè)論文開題報告
- UL1012標準中文版-2018非二類變壓器UL中文版標準
- sqe主管述職報告
- 出納常用表格大全
- 《頭暈與眩暈診斷》課件
- 2022年江蘇職教高考市場營銷試卷
評論
0/150
提交評論