劍指offer 題解 python編程

目錄

第12題  矩陣中的路徑

解體思路


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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章