剑指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))

 

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