剑指offer 题9,12-18 python题解记录

本文探讨如何通过两个栈实现队列的数据结构,并运用深度优先搜索解决矩阵路径问题及机器人运动范围。讲解了队列模拟、路径遍历算法和机器人行动策略的优化技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题9:用两个栈实现队列

队列是先进先出,栈是先进后出,两个栈实现队列的基本思想就是:数据从stack1进入,再将stack1中的数据倒到stack2中,那么从stack2中出来的数据顺序就和进入stack1中的数据顺序一样了,也就实现了队列。处理细节就是,有数据进入时,只管往stack1中添加,当需要取出数据时,只管从stack2中取,如果stack2为空,那么就把stack1中的元素倒到stack2中(妙喵喵~
王先生题解👉here

class CQueue:
    def __init__(self):
        self.instack = []
        self.outstack = []
    def appendTail(self, value: int) -> None:
        self.instack.append(value)
    def deleteHead(self) -> int:
        if len(self.outstack)==0:
            if len(self.instack)==0:
                return -1
            else:
                while len(self.instack) !=0 :
                    self.outstack.append(self.instack.pop())
                return self.outstack.pop()
        else:
            return self.outstack.pop()

题12:矩阵中的路径

我的错解👇,出错用例:[["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]] "SEE",错误原因是,s周围有两个e可选,但我的while if 导致每次都会先选择s上方的e,没法走到s下方的e,解决起来太麻烦了,放弃

class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        n,m,find = len(board),len(board[0]),0
        if n*m<len(word) or len(word)==0:
            return False
        if len(word)==1 and word[0] in board:
            return True
        visit = [[0]*m for _ in range(n)]
        record = [0]*len(word)
        word = word.upper()
        for i in range(n):
            for j in range(m):
                if board[i][j].upper()==word[find]:
                    record[find]=(i,j)
                    visit[i][j]=1
                    a,b=i,j
                    find+=1
                    while find<len(word) and find>0:
                        #print(record)
                        if a>0 and board[a-1][b].upper()==word[find] and visit[a-1][b]==0:
                            record[find]=(a-1,b)
                            a,find=a-1,find+1
                        elif a<n-1 and board[a+1][b].upper()==word[find] and visit[a+1][b]==0:
                            record[find]=(a+1,b)
                            a,find=a+1,find+1
                        elif b>0 and board[a][b-1].upper()==word[find] and visit[a][b-1]==0:
                            record[find]=(a,b-1)
                            b,find=b-1,find+1
                        elif b<m-1 and board[a][b+1].upper()==word[find] and visit[a][b+1]==0:
                            record[find]=(a,b+1)
                            b,find=b+1,find+1
                        else:
                            visit[a][b]=0
                            find-=1
                            a,b=record[find]
                    if find == len(word):
                        return True
        return False

王先生的做法👇,思路都是一样的:深度优先遍历,但他的写法就很简洁明了(妙喵喵
在函数里定义函数能省去很多传参的步骤,两个or用的实在是喵

class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        n,m = len(board),len(board[0])
        if n*m<len(word) or len(word)==0:
            return False
        def dfs(i:int,j:int,ind:int)->bool:
            if ind>=len(word):
                return True
            if i<0 or j<0 or i>=n or j>=m or board[i][j]!=word[ind]:
                return False
            board[i][j]=''
            if dfs(i-1,j,ind+1) or dfs(i+1,j,ind+1) or dfs(i,j-1,ind+1) or dfs(i,j+1,ind+1):
                return True
            board[i][j]=word[ind]
            return False
        for i in range(n):
            for j in range(m):
                if dfs(i,j,0):
                    return True
        return False 

题13:机器人的运动范围

和题12的思想是一致的,都是深度优先搜索,满足条件则res++,否则不操作
注意:函数嵌套时,想在子函数中引用父函数中的变量,需要在子函数里对所引用变量进行nonlocal声明;
python里的除法不像C语言里的除法一样,需要int转换一下

class Solution:
    def movingCount(self, m: int, n: int, k: int) -> int:
        visit = [[0]*n for _ in range(m)]
        res = 0
        def dfs(x:int,y:int):
            nonlocal res
            print(x,y,res,self.mysum(x,y))
            if 0<=x<m and 0<=y<n and visit[x][y]==0:
                visit[x][y]=1
                if self.mysum(x,y)<=k:
                    res += 1
                    dfs(x+1,y)
                    dfs(x-1,y)
                    dfs(x,y+1)
                    dfs(x,y-1)
        dfs(0,0)
        return res
    def mysum(self,n:int,m:int)->int:
        s = 0
        while n!=0:
            s += n%10
            n=int(n/10)
        while m!=0:
            s += m%10
            m =int(m/10)
        return s

题14-1&14-2:剪绳子

法一:本菜鸡自己独立想到的,可喜可贺,PS:还比某人的要快哈哈哈哈
思想:长度为n的绳子分成m段,自然是均分得到的连乘结果最大,如果存在余数,则将余数分成r个1,再加到r个avg上,即,11米长的绳子分成3段,均分可以得到3个3米长的绳子,还余2米,则将这2米分别加到两个3米子绳子上,即最终得到的结果为【3,4,4】;而一共有m种分法,遍历取最大值即可

class Solution:
    def cuttingRope(self, n: int) -> int:
        maxmun = 0
        for i in range(2,n+1):
            res = n%i
            avg = int((n-res)/i)
            if res == 0:
                mul = avg**i
            else:
                mul = avg**(i-res)*(avg+1)**res
            if mul > maxmun:
                maxmun = mul
        return maxmun%1000000007

法二:动态规划
每次仅考虑将长度为i的绳子分成两段,则这个子问题的最优解就等于dp[i]=dp[k]*dp[i-k],剽窃王先生的描述:
定义:dp[i] 表示长度为i的绳子至少分割成两段(m>1)的最大连乘。
转移方程:dp[i]=dp[k]*dp[i-k],(其中0<k<i)
此时未考虑子问题不分割绳子的情况(即子问题仅有一段绳子),遂加上:

dp[i]=dp[k](i-k)
dp[i]=k*dp[i-k]
dp[i]=k*(i-k)

完整代码如下:

class Solution:
    def cuttingRope(self, n: int) -> int:
        dp = [0]*(n+1) #初始化
        dp[1]=1
        for i in range(2,n+1):
            for j in range(1,int(i/2)+1): #避免重复计算dp[k]*dp[i-k]==dp[i-k]*dp[k]
            #每次选取最优解即可
                dp[i]=max(dp[i],dp[j]*dp[i-j],dp[j]*(i-j),j*dp[i-j],j*(i-j))
        return dp[n]

题15:二进制中1的个数

法一:新姿势 bin函数可以返回int的二进制字符串,count可以查找某个值出现的次数,不仅可以查找字符串,也可以查找列表(面向对象的特性)

class Solution:
    def hammingWeight(self, n: int) -> int:
        return bin(n).count('1') 
        #bin返回int的二进制字符串;count用于查找字符串中某个子串/元素出现的次数。可指定start和end

其他方法:求余、左右移……

题16:数值的整数次方

求x的n次方,即快速幂,搬运王先生的描述:
将n次幂转换为(1+2+4+8+16+…)次幂。
即将n转为其二进制,若其二进制当前位数为1则乘上其对应的幂即可,为0则跳过。
负幂,先当作正幂算,最后用1去除以即可。

class Solution:
    def myPow(self, x: float, n: int) -> float:
        res,cur = 1,x
        for i in bin(abs(n))[::-1]:
            if i == '1':
                res *= cur
            cur *= cur
        if n<0:
            res = 1/res
        return res

题17:打印从1到最大的n位数

python不存在整数溢出问题,所以很方便

class Solution:
    def printNumbers(self, n: int) -> List[int]:
        return [i for i in range(1,10**n)]

题18:删除链表的节点

链表的删除,已掌握,过
注意删除头节点的情况

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def deleteNode(self, head: ListNode, val: int) -> ListNode:
        pre,now = head,head
        while now != None:
            if now.val == val:
                if now==head:
                    head = head.next
                    break
                else:
                    pre.next=now.next
                    break
            else:
                pre=now
                now=now.next
        return head
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值