目錄
第12題 矩陣中的路徑
請設計一個函數,用來判斷在一個矩陣中是否存在一條包含某字符串所有字符的路徑。路徑可以從矩陣中的任意一個格子開始,每一步可以在矩陣中向左,向右,向上,向下移動一個格子。如果一條路徑經過了矩陣中的某一個格子,則該路徑不能再進入該格子。 例如[ ['a','b','t','g'],['c','f','c','s'],['j','d','e','h'] ] 矩陣中包含一條字符串”abtgs”的路徑,但是矩陣中不包含”abbt”路徑,因爲字符串的第二個字符b佔據了矩陣中的第一行第二個格子之後,路徑不能再次進入該格子。
解體思路
利用回溯法求解,hadfind表示當前是第幾個字母的位置需要進行判斷,walk表示字母是否在之前已經走過,False爲沒走過,True爲走過,arr矩陣被展開爲列表形式,i,j定位當且路徑點,str爲目標字符串。
1、遍歷列表中的一個點作爲起始點,之後判斷改該點是否滿足條件,不超出索引範圍,沒被走過,當前路徑點與目標字符串相應位置相同,
2、滿足,標記該點walk=True,選擇其上下左右的位置,判斷其是否滿足1中條件,滿足,執行2,否則,執行3
3、不滿足,將該點walk改寫爲False,回退上一步2的位置,找其上下左右未選擇的位置,選擇下一步位置,若所有位置均不滿足要求,標記此時的位置walk爲False,再次回退;
4、當hadfind達到str的長度時,證明遍歷結束,目標找到,返回True
def hasPath(arr,str,rows,cols):
if not arr or not str or rows<1 or cols<1:
return False
hadfind=0
walk=[False]*rows*cols
for i in range(rows):
for j in range(cols):
if find_path(arr,str,rows,cols,i,j,hadfind,walk):
return True
return False
def find_path(arr,str,rows,cols,i,j,hadfind,walk):
if hadfind>=len(str):
return True
index=i*cols+j
if i<0 or j<0 or i>=rows or j>=cols or arr[index]!=str[hadfind] or walk[index]:
return False
walk[index] = True
if find_path(arr,str,rows,cols,i+1,j,hadfind+1,walk) or find_path(arr,str,rows,cols,i-1,j,hadfind+1,walk) or \
find_path(arr,str,rows,cols,i,j+1,hadfind+1,walk) or find_path(arr,str,rows,cols,i,j-1,hadfind+1,walk):
return True
walk[index]=False
return False
k=['a','b','t','g','c','f','c','s','j','d','e','h']
s='abtgs'
r=3
c=4
print(hasPath(k,s,r,c))
13 機器人的運動範圍
地上有一個m行和n列的方格。一個機器人從座標0,0的格子開始移動,每一次只能向左,右,上,下四個方向移動一格,但是不能進入行座標和列座標的數位之和大於k的格子。 例如,當k爲18時,機器人能夠進入方格(35,37),因爲3+5+3+7 = 18。但是,它不能進入方格(35,38),因爲3+5+3+8 = 19。請問該機器人能夠達到多少個格子?
解題思路
課本用回溯法進行題解,我覺得完全可以用遍歷進行
def get_sum(i):
sum=0
while i>0:
sum+=i%10
i=i//10
return sum
def walkAccessible(row,col,i,j,k,walk):
sum=get_sum(i)+get_sum(j)
if i>=0 and i<row and j>=0 and j<col and sum<=k and not walk[i][j]:
return True
return False
def RobotWalk(row,col,i,j,k,walked):
count=0
if walkAccessible(row,col,i,j,k,walked):
walked[i][j] = True
count=1+RobotWalk(row,col,i-1,j,k,walked)+RobotWalk(row,col,i,j-1,k,walked)+RobotWalk(row,col,i,j+1,k,walked)+\
RobotWalk(row,col,i+1,j,k,walked)
return count
def Robot(row,col,k):
if k<0:
return 0
if row<1 or col<1:
raise ValueError('Invalid!')
walked=[[False]*col for _ in range(row)]
count=RobotWalk(row,col,0,0,k,walked)
print(walked)
return count
print(Robot(10,10,8))
14 剪繩子
給定一根長度爲n的繩子,請把繩子剪成m段(m、n都是整數,n>1並且m>1),每段繩子的長度記爲k[0],k[1],…,k[m]。請問k[0]* k[1] * … *k[m]可能的最大乘積是多少?
解題思路
利用動態規劃,將f(n)分解爲求max(f(i)*f(n-i)),要注意,這裏利用了一個規律,如果f(n)可以分解兩段長度乘積大於n,那麼我們對該段進行分解,即如果f(n)>=n,那麼n要進行至少一次分段,對於n=1,無法分段,n=2,只可分爲1*1<2,n=3,可分爲1*2或者1*1*1,最大爲2,2<3,對於4,可分爲1*3,2*2,兩種,對於1*3這種情況,由於3分解後不大於自身,不分解,只有兩種情況,最大爲4,5分解爲2*3,1*2*2,2,3再分解均小於自身,所以最大爲6。因此採用遍歷法計算各長度可能的最大值。
def cutRole(length):
if type(length)!=int:
raise TypeError('not an int')
if length<=1:
return 0
if length==2:
return 1
if length==3:
return 2
products=[0]*(length+1)
products[0]=0
products[1]=1
products[2]=2
products[3]=3
for i in range(4,length+1):
max=0
for j in range(1,i):
if products[j]*products[i-j]>max:
max=products[j]*products[i-j]
products[i]=max
return products[-1]
print(cutRole(4))
15 二進制中1的個數
輸入一個整數,輸出該數二進制表示中1的個數。其中負數用補碼錶示。
解題思路
如果一個整數不爲0,那麼這個整數至少有一位是1。如果我們把這個整數減1,那麼原來處在整數最右邊的1就會變爲0,原來在1後面的所有的0都會變成1(如果最右邊的1後面還有0的話)。其餘所有位將不會受到影響。把原來的整數和減去1之後的結果做與運算,從原來整數最右邊一個1那一位開始所有位都會變成0。
但是要注意python中的數字長度會有變化,因此按照課本上的思路進行編程時,會出現錯誤,即負數無法正常輸出,因此要添加限制條件,利用0xffffffff將其限制在32位內。詳見博客
def NumberOfOne(n):
count=0
while n&0xffffffff != 0:
#利用0xffffffff限值在32位之內
count+=1
n=n&(n-1)
return count
print(NumberOfOne(-3))