手撕算法面试题集锦(剑指offer)_python实现

这篇博客详细介绍了多种数据结构与算法的面试题目,包括链表(如链表反转、合并排序链表等)、树(如二叉树的镜像、对称判断等)、数组(如旋转数组找最小值、删除重复节点等)和字符串(如字符串旋转、转换整数等)的Python实现,旨在帮助读者巩固和提升算法能力。
摘要由CSDN通过智能技术生成

持续更新中…


文章目录

1 链表

1.1 从尾到头打印链表

输入一个链表,按链表值从尾到头的顺序返回一个 List 。

class Solution:
    # 返回从尾部到头部的列表值序列,例如[1,2,3]
    def printListFromTailToHead(self, listNode):
        # write code here
        return_list = []
        while listNode:
            return_list.insert(0,listNode.val)
            listNode = listNode.next
        return return_list

1.2 链表中倒数第k个结点

输入一个链表,输出该链表中倒数第k个结点。

class Solution:
    def FindKthToTail(self, head, k):
        # write code here
        if head is None:
            return head
        pPre = head
        pBack = head
        for i in range(k):
            if pPre is None:
                return None
            pPre = pPre.next
        while pPre is not None:
            pPre = pPre.next
            pBack = pBack.next
        return pBack

1.3 反转链表

输入一个链表,反转链表后,输出新链表的表头。

class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        # write code here
        if pHead is None:
            return pHead
        if pHead.next is None:
            return pHead
        pPre = None
        while pHead:
            tmp = pHead.next
            pHead.next = pPre
            pPre = pHead
            pHead = tmp
        return pPre

1.4 合并两个排序的链表

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

class Solution:
    # 返回合并后列表
    def Merge(self, pHead1, pHead2):
        # write code here
        if pHead1 is None and pHead2 is None:
            return None
        if pHead1 is None:
            return pHead2
        if pHead2 is None:
            return pHead1
        pHead = ListNode(None)
        pRet = pHead
        while pHead1 and pHead2:
            if pHead1.val > pHead2.val:
                pHead.next = pHead2
                pHead = pHead.next
                pHead2 = pHead2.next
            else:
                pHead.next = pHead1
                pHead = pHead.next
                pHead1 = pHead1.next
        while pHead1:
            pHead.next = pHead1
            pHead = pHead.next
            pHead1 = pHead1.next
        while pHead2:
            pHead.next = pHead2
            pHead = pHead.next
            pHead2 = pHead2.next
        return pRet.next

1.5 链表中环的入口结点

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出None。

思路简述快慢指针思想的应用。

Step1:快慢指针都指向头节点;
Step2:每一次操作快指针走两步(执行两次 .next),慢指针走一步(执行一次 .next);
Step3:循环执行Step2,当快慢指针相遇,则说明两个指针均在某一个环中;
Step4:慢指针不动,快指针每次走一步,环中节点数加一(num_of_node_circle +1);
Step5:循环执行Step4,当快慢指针再一次相遇,此时快指针绕环一圈,num_of_node_circle即为环中节点个数;
Step6:此时,可以根据 “1.2 链表中倒数第k个结点” 的思路,找到环的入口处。

class Solution:
    def EntryNodeOfLoop(self, pHead):
        # write code here
        if pHead is None or pHead.next is None:
            return None
        pFast = pHead.next
        pSlow = pHead
        # Find the circle
        while pFast != pSlow:
            pFast = pFast.next
            pFast = pFast.next
            pSlow = pSlow.next
            if pFast is None:
                return None
        # Count the number of node in circle
        num_of_node_circle = 1
        pFast = pFast.next
        while pFast != pSlow:
            num_of_node_circle = num_of_node_circle+1
            pFast = pFast.next
        pFast = pHead
        # Find the entrance of the circle
        for i in range(num_of_node_circle):
            pFast = pFast.next
        while pFast != pHead:
            pHead =pHead.next
            pFast = pFast.next
        return pHead

1.6 两个链表的第一个公共结点

输入两个链表,找出它们的第一个公共结点。

class Solution:
    def FindFirstCommonNode(self, pHead1, pHead2):
        # write code here
        if not pHead1:return None
        if not pHead2:return None
        length_pHead1 = 0
        length_pHead2 = 0
        p_head_1 = pHead1
        p_head_2 = pHead2
        while p_head_1:
            length_pHead1 = length_pHead1+1
            p_head_1 = p_head_1.next
        while p_head_2:
            length_pHead2 = length_pHead2+1
            p_head_2 = p_head_2.next
        if length_pHead1 > length_pHead2:
            for i in range(length_pHead1 - length_pHead2):
                pHead1 = pHead1.next
        else:
            for i in range(length_pHead2 - length_pHead1):
                pHead2 = pHead2.next
        while pHead1 != pHead2:
            pHead1 = pHead1.next
            pHead2 = pHead2.next
        return pHead1

1.7 复杂链表的复制

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

class Solution:
    # 返回 RandomListNode
    def Clone(self, pHead):
        pNode = self.CloneNode(pHead)
        pNode = self.ConnectRandomNodes(pNode)
        return self.ReconnectNodes(pNode)
    def CloneNode(self, pHead):
        pNode = pHead
        while pNode is not None:
            pCloned = RandomListNode(pNode.label)
            pCloned.next = pNode.next
            pNode.next = pCloned
            pNode = pCloned.next
        return pHead
    def ConnectRandomNodes(self, pHead):
        pNode = pHead
        while pNode is not None:
            pCloned = pNode.next
            if pNode.random is not None:
                pCloned.random = pNode.random.next
            pNode = pCloned.next
        return pHead
    def ReconnectNodes(self, pHead):
        pNode = pHead
        pClonedHead = pHead
        if pNode is not None:
            pClonedNode = pNode.next
            pClonedHead = pNode.next
            pNode.next = pClonedNode.next
            pNode = pNode.next
        while pNode is not None:
            pClonedNode.next = pNode.next
            pClonedNode = pClonedNode.next
            pNode.next = pClonedNode.next
            pNode = pNode.next
        return pClonedHead

1.8 二叉搜索树与双向链表

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

class Solution:
    def Convert(self, pRootOfTree):
        # write code here
        pLastNodeInList = None
        pLastNodeInList = self.CovertNode(pRootOfTree, pLastNodeInList)
        pHeadOfList = pLastNodeInList
        while pHeadOfList is not None and pHeadOfList.left is not None:
            pHeadOfList = pHeadOfList.left
        return pHeadOfList
    def CovertNode(self, pNode, pLastNodeInList):
        if pNode is None:
            return 
        pCurrent = pNode
        if pCurrent.left is not None:
            pLastNodeInList = self.CovertNode(pCurrent.left, pLastNodeInList)
        pCurrent.left = pLastNodeInList
        if pLastNodeInList is not None:
            pLastNodeInList.right = pCurrent
        pLastNodeInList = pCurrent
        if pCurrent.right is not None:
            pLastNodeInList = self.CovertNode(pCurrent.right, pLastNodeInList)
        return pLastNodeInList

1.9 删除链表中重复的节点

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5 。

class Solution:
    def deleteDuplication(self, pHead):
        if pHead is None:
            return pHead
        pSlow = ListNode(None)
        pSlow.next = pHead
        pFast = pHead
        pHead = pSlow
        flag_duplication = False
        while pFast and pFast.next:
            tmp_val = pFast.val
            pFast = pFast.next
            if tmp_val == pFast.val:
                flag_duplication = True
            elif flag_duplication:
                flag_duplication = False
                pSlow.next = pFast
            else:
                pSlow = pSlow.next
        if pSlow.next != pFast:
            pSlow.next = None
        return pHead.next

2 树

2.1 二叉树的镜像

操作给定的二叉树,将其变换为源二叉树的镜像。
在这里插入图片描述

class Solution:
    # 返回镜像树的根节点
    def Mirror(self, root):
        # write code here
        if root is None:
            return 
        if root.left is None and root.right is None:
            return 
        root.left,root.right = root.right,root.left
        if root.left:
            self.Mirror(root.left)
        if root.right:
            self.Mirror(root.right)

2.2 对称的二叉树

请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

class Solution:
    def isSymmetrical(self, pRoot):
        # write code here
        return self.isSymmetrical_rec(pRoot,pRoot)
    def isSymmetrical_rec(self,pRoot1,pRoot2):
        if pRoot1 is None and pRoot2 is None:
            return True
        if pRoot1 is None or pRoot2 is None:
            return False
        if pRoot1.val != pRoot2.val:
            return False
        return self.isSymmetrical_rec(pRoot1.left,pRoot2.right) and self.isSymmetrical_rec(pRoot1.right,pRoot2.left)

2.3 从上往下打印二叉树

从上往下打印出二叉树的每个节点,同层节点从左至右打印。

class Solution:
    # 返回从上到下每个节点值列表,例:[1,2,3]
    def PrintFromTopToBottom(self, root):
        if root is None:
            return []
        return_list = []
        queue = []
        queue.append(root)
        while len(queue):
            root = queue.pop(0)
            return_list.append(root.val)
            if root.left:
                queue.append(root.left)
            if root.right:
                queue.append(root.right)
        return return_list

2.4 二叉树的下一个结点

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

class Solution:
    def GetNext(self, pNode):
        # write code here
        if pNode is None:
            return None
        pNext = None
        if pNode.right:
            pRight = pNode.right
            while pRight.left:
                pRight = pRight.left
            pNext = pRight
        elif pNode.next:
            pCurrent = pNode
            pParent = pNode.next
            while pParent and pCurrent == pParent.right:
                pCurrent = pParent
                pParent = pParent.next
            pNext = pParent
        return pNext

2.5 重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

class Solution:
    # 返回构造的TreeNode根节点
    def reConstructBinaryTree(self, pre, tin):
        # write code here
        if len(pre) == 0:
            return None
        if len(pre) == 1:
            return TreeNode(pre[0])
        else:
            root = TreeNode(pre[0])
            root.left = self.reConstructBinaryTree(pre[1:tin.index(pre[0])+1],tin[:tin.index(pre[0])])
            root.right = self.reConstructBinaryTree(pre[tin.index(pre[0])+1:],tin[tin.index(pre[0])+1:])
        return root

2.6 二叉树的深度

输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

class Solution:
    def TreeDepth(self, pRoot):
        # write code here
        if pRoot is None:
            return 0
        n_left = self.TreeDepth(pRoot.left)
        n_right = self.TreeDepth(pRoot.right)
        if n_left > n_right:
            return n_left + 1
        else:
            return n_right + 1

2.7 树的子结构

输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

class Solution:
    def HasSubtree(self, pRoot1, pRoot2):
        # write code here
        result = False
        if pRoot1 is not None and pRoot2 is not None:
            if pRoot1.val == pRoot2.val:
                result = self.DoesTree1HaveTree2(pRoot1, pRoot2)
            if not result:
                result = self.HasSubtree(pRoot1.left, pRoot2)
            if not result:
                result = self.HasSubtree(pRoot1.right, pRoot2)
        return result
    def DoesTree1HaveTree2(self, pRoot1, pRoot2):
        if pRoot2 is None:
            return True
        if pRoot1 is None:
            return False
        if pRoot1.val != pRoot2.val:
            return False
        return self.DoesTree1HaveTree2(pRoot1.left, pRoot2.left) and self.DoesTree1HaveTree2(pRoot1.right, pRoot2.right)

2.8 二叉搜索树的后序遍历序列

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

class Solution:
    def VerifySquenceOfBST(self, sequence):
        # 二叉搜索树的后序遍历,最后一个为根节点,前面分为两部分
        # 左边部分数值都小于根节点(左子树),右边部分数值都大于根节点的数值(右子树)
        # 子树的后序遍历满足以上规律
        if not sequence:
            print(1)
            return False
        root = sequence[-1]
        # 找到左子树(可能为空)
        idx_i = 0
        while sequence[idx_i]<root:
            idx_i = idx_i+1
        # 剩下的部分为右子树(可能为空),若其中有数值小于根节点,则不满足二叉搜索树的条件
        for j in range(idx_i,len(sequence)-1):
            if sequence[j] < root:
                return False
        # 递归判断左右子树是否满足二叉搜索树的条件
        left = True
        # idx_i>0表明左子树不为空,sequence[:idx_i]为原序列左子树的部分
        if idx_i > 0:
            left = self.VerifySquenceOfBST(sequence[:idx_i])
        right = True
        # idx_i < len(sequence)-1表明右子树不为空,
        # sequence[idx_i:len(sequence)-1]为原序列右子树的部分
        if idx_i < len(sequence)-1:
            right = self.VerifySquenceOfBST(sequence[idx_i:len(sequence)-1])
        return left and right

2.9 二叉树中和为某一值的路径

输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)

class Solution:
    # 返回二维列表,内部每个列表表示找到的路径
    def __init__(self):
        self.path = []
        self.result = []
    def FindPath(self, root, expectNumber):
        if not root:
            return 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值