剑指Offer(上)1-35题实现 python版本

这篇博客汇总了剑指Offer系列算法题的Python解法,包括数组中重复数字、二维数组查找、替换空格等,涉及哈希表、栈、递归、二叉树遍历等多种数据结构和算法。作者通过实际题目解析,提供了详细的解题思路和代码实现。
摘要由CSDN通过智能技术生成

剑指offer合集,主要是记录一下做题过程,给自己以后复习用,借鉴了很多别的大佬的做题思路。

36-75题:下半部分链接https://blog.csdn.net/chuxuezheerer/article/details/107985913

文章目录

1.剑指 Offer03. 数组中重复的数字

构造哈希表,或者用数组位置记录,如果大于1,则有重复。
(1)小偷懒,用Python内部函数实现:

class Solution:
    def findRepeatNumber(self, nums: List[int]) -> int:
        res=collections.Counter(nums)
        for key in res:
            if res[key]>1:
                return key

在这里插入图片描述

(2)构造哈希

class Solution:
    def findRepeatNumber(self, nums: List[int]) -> int:
        res={
   }
        for ch in nums:
            if ch not in res:
                res[ch]=1
            else:
                return ch

在这里插入图片描述

2.剑指 Offer 04. 二维数组中的查找

在这里插入图片描述
找到这个二维数组的特点

class Solution:
    def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
        if not matrix:
            return False
        #从右上角开始,大于该数向下走,小于向左走
        n=len(matrix)
        m=len(matrix[0])
        i,j=0,m-1
        while 0<=i<n and 0<=j<m:
            if matrix[i][j]==target:
                return True
            elif matrix[i][j]<target:
                i+=1
            else:
                j-=1
        return False

3.剑指 Offer 05. 替换空格

在这里插入图片描述
其实就是把占位一个字符的空格替换为占位三个字符的%20.
要注意使用python语言时,字符串是一个不可变数组,所以最好新建一个list,在list中进行操作。

class Solution:
    def replaceSpace(self, s: str) -> str:
        res=[]
        for ch in s:
            if ch==' ':
                res.append("%20")
            else:
                res.append(ch)
                
        return  "".join(res)

4.剑指 Offer 06. 从尾到头打印链表

在这里插入图片描述
用一个栈来辅助

class Solution:
    def reversePrint(self, head: ListNode) -> List[int]:
        res=[]
        while head:
            res.append(head.val)
            head=head.next
            
        return res[::-1]

5.剑指 Offer 07. 重建二叉树

在这里插入图片描述
前序遍历:根左右。中序遍历:左根右。
递归思想,前序遍历中pre_left为结点的根,之后在中序遍历中寻找,获得值为pre_left的下标位置,左边的为左子树,右边的是右子树。
递归,从前序中获得根节点位置,从中序中获得子树长度。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        #前序:根左右
        #中序:左根右
        self.preRootDict={
   }
        self.pre=preorder
        
        for i in range(len(inorder)):
            self.preRootDict[inorder[i]]=i #记录中序结点的位置
        return self.getRoot(0,0,len(inorder)-1)#根结点,中序遍历范围
    
    def getRoot(self,preRoot,inorderLeft,inorderRight):
        if inorderLeft>inorderRight: #中序遍历为空
            return
        root=TreeNode(self.pre[preRoot]) #建立根结点
        i=self.preRootDict[self.pre[preRoot]] #找到前序中根结点在中序中的位置
        
        root.left=self.getRoot(preRoot+1,inorderLeft,i-1)
        #preRoot当前的根  左子树的长度 = 左子树的右边-左边 (i-1-inorderLeft+1) 。最后+1就是右子树的根了
        root.right=self.getRoot(preRoot+i-inorderLeft+1,i+1,inorderRight)
        
        return root               

在这里插入图片描述

6.剑指 Offer09. 用两个栈实现队列

在这里插入图片描述

class CQueue:

    def __init__(self):
        self.stack1=[]
        self.stack2=[]


    def appendTail(self, value: int) -> None:
        self.stack1.append(value)


    def deleteHead(self) -> int:
        if self.stack2:
            return self.stack2.pop()
        else:
            if self.stack1:
                while self.stack1:
                    self.stack2.append(self.stack1.pop())
                    
                return self.stack2.pop()
            else:
                return -1
            

7.剑指 Offer 10- I. 斐波那契数列

在这里插入图片描述
这一看就是动态数组问题。但常规的F(n)=F(n-1)+F(n-2)这种方法输入会超时。所以用一个辅助的字典记录已经算过的值。

class Solution:
    def fib(self, n: int) -> int:
        
        if n<=0:
            return 0
        arr={
   }
        return self.fibNum(arr,n)%1000000007
    
    def fibNum(self,arr,n):
        if n==1 or n==2:
            return 1
        
        if n in arr:
            return arr[n] #记录以前已经算过的值,若已经存在则直接返回。
        
        arr[n]=self.fibNum(arr,n-1)+self.fibNum(arr,n-2)
        
        return arr[n]
            

在这里插入图片描述

还有一种方法,相对简单。

class Solution:
    def fib(self, n: int) -> int:
        a, b = 0, 1
        for _ in range(n):
            a, b = b, a + b
        return a % 1000000007

差不多 …(甩锅给leetcode…)
在这里插入图片描述

8.剑指 Offer 10- II. 青蛙跳台阶问题

在这里插入图片描述

解题思路同上道题,第n个台阶,不是从n-1个台阶上来就是从n-2个台阶上来。

class Solution:
    def numWays(self, n: int) -> int:
        if n<=0:
            return 1
        arr={
   }
        return (self.f(arr,n))%1000000007
        
        
    def f(self,arr,n):      
        if n==1:
            return 1
        elif n==2:
            return 2
        if n in arr:
            return arr[n]
        
        arr[n]=self.f(arr,n-1)+self.f(arr,n-2)
        return arr[n]
                

在这里插入图片描述

9.剑指 Offer 11. 旋转数组的最小数字

在这里插入图片描述
借鉴:某位大佬写的更加详细
二分法的思想

class Solution:
    def minArray(self, numbers: [int]) -> int:
        i, j = 0, len(numbers) - 1
        while i < j:
            m = (i + j) // 2 #中心点
            if numbers[m] > numbers[j]: i = m + 1 #若右侧的点小于中心位置的点,则说明旋转点在中心位置的右侧
            elif numbers[m] < numbers[j]: j = m #若右侧的点大于中心位置的点,则说明旋转点在中心位置的左侧
            else: j -= 1 #若相等,则情况不明需要进一步判断(比如01011111和123123两种旋转点不一样)
        return numbers[i]

在这里插入图片描述

10.剑指 Offer 12. 矩阵中的路径

在这里插入图片描述
这道题利用深度优先遍历+回溯思想。

class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        def dfs(i,j,k):
            if not 0<=i<len(board) or not 0<=j<len(board[0]) or board[i][j]!=word[k]:
                return False
            if k==len(word)-1:
                return True
            #用一个临时值存储当前值,用于回溯
            tmp,board[i][j]=board[i][j],'/'
            #进行深度遍历
            res=dfs(i+1,j,k+1) or dfs(i-1,j,k+1) or dfs(i,j+1,k+1) or dfs(i,j-1,k+1)
            board[i][j]=tmp
            return
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值