剑指offer 题20-33 Python题解记录

题20:表示数值的字符串

我的做法更复杂一点,因为之前没有考虑到科学计数法前半部分也可以是浮点数。主要是分情况讨论,分别处理:1)含有e时;2)不含e但含有.时3)既不含e也不含.时;这三种情况。同时,将有符号数和无符号数的判断集成为了函数;

class Solution:
    def isNumber(self, s: str) -> bool:
        s = s.strip() #去掉字符串的首尾空格
        if s != '' and (s[0] == '+' or s[0] == '-'):#先处理首次出现的符号(其实也可以不处理)
            s = s[1:]
        def isUnsigned(sub: str) -> bool:#判断sub是否为无符号整数
            if len(sub)==0:
                return False
            for i in sub:
                if i not in ['0','1','2','3','4','5','6','7','8','9']:
                    return False
            return True
        def isSigned(sub: str) -> bool:#判断sub是否为有符号整数
            if len(sub)==0:
                return False
            return (sub[0]=='+' or sub[0]=='-') and isUnsigned(sub[1:])
        ind = max(s.find('e'),s.find('E'))#寻找s中是否存在e,若存在,则返回e所在下标,否则返回-1
        if ind == -1: #不存在e
            ind = s.find('.')#不存在e时,再判断是否存在.
            if ind == -1: #若不存在.
                return (isUnsigned(s) or isSigned(s))#判断是否为整数
            else:#存在.,分为两段,对前后两段分别判断,注意,两段中可有一段为空
                suba = s[:ind]
                subb = '' if ind == len(s)-1 else s[ind+1:]
                if suba == '' and subb == '':
                    return False
                elif suba == '':
                    return isUnsigned(subb)
                elif subb == '':
                    return (isUnsigned(suba) or isSigned(suba))
                else:
                    return ((isUnsigned(suba) or isSigned(suba)) and isUnsigned(subb))
        else:#存在e
            suba = s[:ind]
            subb = '' if ind == len(s)-1 else s[ind+1:]
            if suba == '' or subb == '':
                return False
            else:
                ind = suba.find('.')
                if ind == -1:
                    return ((isUnsigned(suba) or isSigned(suba)) and (isUnsigned(subb) or isSigned(subb)))
                else:
                    if isSigned(subb) or isUnsigned(subb):
                        saa = suba[:ind]
                        sab = '' if ind == len(suba)-1 else suba[ind+1:]
                        if saa == '' and sab == '':
                            return False
                        else:
                            return ((saa == '' or isUnsigned(saa)) and (sab == '' or isUnsigned(sab)))
                    else:
                        return False

更简单的做法:只以e为分隔符,分前后两段,然后对每一段进行逐个字符的判断,利用两个flag(havedot、havenum)去判断是否出现重复逗点等情况,👉题解链接

class Solution:
    def isNumber(self, s: str) -> bool:
        #处理多余空格
        s=s.strip()
        #分隔字符
        pre,pst='',''
        ind = s.find('e')
        pre = s[:ind] if ind!=-1 else ''
        pst = '' if ind == len(s)-1 else s[ind+1:]
        # 数字部分
        if len(pre) == 0:
            return False
        havedot ,havenum=False,False
        for i in range(len(pre)):
            if pre[i]=='+' or pre[i]== '-':
                if i!=0:
                    return False
            elif pre[i]=='.' :
                if not havedot:
                    havedot =True
                else :
                    return False
            elif '0'<=pre[i]<='9':
                havenum =True
            else :
                return False
        if not havenum :
            return False
        # 指数部分
        if pre != s and len(pst)==0:
            return False
        havenum = False
        for i in range(len(pst)):
            if pst[i] == '-' or pst[i] == '+':
                if i != 0:
                    return False
            elif pst[i]=='.':
                return False
            elif '0'<=pst[i]<='9':
                havenum = True
            else :
                return False
        if not havenum and len(pst)>0:
            return False
        return True


题21:调整数组顺序使奇数位于偶数前面

法一:暴力遍历

class Solution:
    def exchange(self, nums: List[int]) -> List[int]:
        even,odd = [],[]
        for i in nums:
            if i%2==0:
                even.append(i)
            else:
                odd.append(i)
        return odd+even

法二:双指针👉详细题解
head指针从首部开始查,直到遇到偶数停下;end指针从尾部向前查,直到遇到奇数停下;如果head>=end,则结束,否则,交换两个指针在nums中对应的数值

class Solution:
    def exchange(self, nums: List[int]) -> List[int]:
        head,end =0, len(nums)-1
        while head<end:
            while nums[head]%2==1 and head<end:
                head+=1
            while nums[end]%2==0 and end>head:
                end-=1
            if head>=end: #注意这一步判断!
                break
            nums[head],nums[end] = nums[end],nums[head]
        return nums

题22:链表中倒数第k个节点

法一:暴力遍历

class Solution:
    def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:
        # 思路:一次遍历记录下所有点,再切片【毫无技术含量
        l=[]
        while head!=None:
            l.append(head)
            head=head.next
        llen = len(l)
        if k>llen:
            return None
        return l[-k]

法二:快慢指针

class Solution:
    def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:
        #正解:快慢指针
        fast=head
        low=head
        i=0
        while fast!=None:
            print(fast.val)
            fast=fast.next
            i+=1
            if(i>k):
                low=low.next
        return low

题24:反转链表

链表基本操作,但需要想清楚需要几个指针

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        pre=None
        cur=head
        while cur!=None:
            tmp=cur.next
            cur.next=pre
            pre=cur
            cur=tmp
        return pre

题25:合并两个排序的链表

法一:不创造新的空间,直接插入,注意,需要创造一个头节点来处理头部插入

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        if l1 == None:
            return l2
        elif l2 == None:
            return l1
        head = ListNode(-1)
        head.next = l1
        s1,s2 = head,l1
        p1,p2 = l2,l2.next
        while s2!=None and p1!=None:
            if p1.val <= s2.val:
                s1.next = p1
                p1.next = s2
                s1 = p1
                p1 = p2
                if p2 == None:
                    break
                else:
                    p2 = p2.next
            else:
                s1 = s2
                s2 = s2.next
        if p1!=None:
            s1.next = p1
        return head.next

法二:创造新的空间,这样更简单,不需要过多的指针操作

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        cur = dum = ListNode(0)
        while l1 and l2:
            if l1.val < l2.val:
                cur.next, l1 = l1, l1.next
            else:
                cur.next, l2 = l2, l2.next
            cur = cur.next
        cur.next = l1 if l1 else l2
        return dum.next

题26: 树的子结构

借鉴王先生的题解:两个递归,一个递归实现深度遍历A,另一个递归实现判断是否满足子结构,很巧妙
利用isSubStructure函数实现对A的遍历,judge函数用户判断当前的A是否包含B这个子结构。
子结构判断:如果B走到了空,则说明匹配了;如果A走到了空或者A的值和B的值不相等,说明不匹配;否则接着判断;

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

class Solution:
    def isSubStructure(self, A: TreeNode, B: TreeNode) -> bool:
        def judge(A,B):
            if B == None:
                return True
            if A == None or A.val != B.val:
                return False
            return judge(A.left,B.left) and judge(A.right,B.right)
        return bool(A and B) and (judge(A,B) or isSubStructure(A.left,B) or isSubStructure(A.right,B))

题27: 二叉树的镜像

凭直觉写出来的递归,比某人的要简洁哈哈哈哈

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

class Solution:
    def mirrorTree(self, root: TreeNode) -> TreeNode:
        if root!=None:
            root.right,root.left=self.mirrorTree(root.left),self.mirrorTree(root.right)
        return root

题28: 对称的二叉树

借鉴了王先生的题解
判断二叉树是否镜像对称:
左子树的左子树等于右子树的右子树
左子树的右子树等于右子树的左子树

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

class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        if root == None:
            return True
        def judge(r1,r2):
            if r1 == None and r2 == None:
                return True
            elif r1 == None or r2 == None:
                return False
            else:
                return judge(r1.right,r2.left) and judge(r1.left,r2.right) if r1.val == r2.val else False
        return judge(root.right,root.left)

题29:

自己想的:以剥离矩阵最外层一圈为单位,重复剥离即可。
设置四个指针:sti指向该剥离的上边缘的行指标,edi表示该剥离的下边缘的行指标,stj表示该剥离的左边缘的列指标,edj表示该剥离的右边缘的列指标。每剥离一次,四个指标向内收缩。

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if len(matrix)==0 or len(matrix[0])==0:
            return matrix
        n,m=len(matrix),len(matrix[0])
        nmmin=min(n,m)
        if nmmin%2==0:
            cir = int(nmmin/2)
        else:
            cir=int(nmmin/2+1)
        sti,edi,stj,edj = 0,n-1,0,m-1
        res=[]
        for ind in range(cir):
            if stj==edj:
                for i in range(sti,edi+1):
                    res.append(matrix[i][edj])
            elif sti==edi:
                for j in range(stj,edj+1):
                    res.append(matrix[sti][j])
            else:
                for j in range(stj,edj+1):
                    res.append(matrix[sti][j])
                for i in range(sti+1,edi+1):
                    res.append(matrix[i][edj])
                for j in range(edj-1,stj-1,-1):
                    res.append(matrix[edi][j])
                for i in range(edi-1,sti,-1):
                    res.append(matrix[i][stj])
            sti+=1
            edi-=1
            stj+=1
            edj-=1
        return res

题30:包含min函数的栈

借鉴王先生的题解
用minst栈来存储前i个数中的最小值,妙

class MinStack:
    def __init__(self):
        self.stack = []
        self.minst = []
    def push(self, x: int) -> None:
        self.stack.append(x)
        if len(self.minst)>0:
            self.minst.append(x if x<self.minst[-1] else self.minst[-1])
        else:
            self.minst.append(x)
    def pop(self) -> None:
        self.stack.pop()
        self.minst.pop()
    def top(self) -> int:
        return self.stack[-1]
    def min(self) -> int:
        if len(self.stack)==0:
            return null
        else:
            return self.minst[-1]
        



# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(x)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.min()

题31:栈的压入、弹出顺序

自己能想到规律,但做不到清晰地整理出来,参考了王先生的题解,相形见绌:
将pushed和popped中的元素从第一个开始逐个比较,分三种情况:
1、两者相同(说明该元素刚入栈就被弹出),继续向下匹配
2、两者不同,再判断出栈元素是否为当前栈中的第一个元素,若相同,将栈中第一个元素弹出,继续向下匹配;
3、若不符合上述两种情况,则说明该模式不合理;
!!仔细看代码

class Solution:
    def validateStackSequences(self, pushed: List[int], popped: List[int]) -> bool:
        n, m = len(pushed), len(popped)
        if m!=n:
            return False
        i, j, stack = 0, 0, []
        while j<m:
            if i<n and pushed[i]==popped[j]:
                i+=1
                j+=1
            elif len(stack)>0 and popped[j]==stack[-1]:
                j+=1
                stack.pop()
            else:
                if i<n:
                    stack.append(pushed[i])   
                i+=1
                if i>=n:
                    break
        return True if j==m else False    

题32-1:从上到下打印二叉树

队列的应用

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

class Solution:
    def levelOrder(self, root: TreeNode) -> List[int]:
        queue,res = [],[]
        if root!=None:
            queue.append(root)
        else:
            return res
        while queue!=[]:
            tmp = queue.pop(0)
            res.append(tmp.val)
            if tmp.left!=None:
                queue.append(tmp.left)
            if tmp.right!=None:
                queue.append(tmp.right)
        return res

题32-2:从上到下打印二叉树

多一个index列表,用于存储每个元素所在行数

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

class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        queue,index,res = [],[],[]
        if root!=None:
            queue.append(root)
            index.append(0)
        else:
            return res
        while len(queue)!=0:
            tmp = queue.pop(0)
            ind = index.pop(0)
            if len(res)==ind:
                res.append([])
            res[ind].append(tmp.val)
            if tmp.left!=None:
                queue.append(tmp.left)
                index.append(ind+1)
            if tmp.right!=None:
                queue.append(tmp.right)
                index.append(ind+1)
        return res

题32-3:从上到下打印二叉树

偶数行倒序输出即可,这是最简单的方法

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

class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        queue,index,res = [],[],[]
        if root!=None:
            queue.append(root)
            index.append(0)
        else:
            return res
        while len(queue)!=0:
            tmp = queue.pop(0)
            ind = index.pop(0)
            if len(res)==ind:
                res.append([])
            res[ind].append(tmp.val)
            if tmp.left!=None:
                queue.append(tmp.left)
                index.append(ind+1)
            if tmp.right!=None:
                queue.append(tmp.right)
                index.append(ind+1)  
        for i in range(len(res)):
            if i%2==1:
                res[i]=res[i][::-1]          
        return res

题33:二叉搜索树的后序遍历序列

二叉搜索树的特点:左子树全部小于根节点,右子树全部大于根节点。那么所给序列必须满足这一特点。【自己想的,时间复杂度应该不是最优】

class Solution:
    def verifyPostorder(self, postorder: List[int]) -> bool:
        flag = 1
        def judge(plist):
            nonlocal flag
            if len(plist)>1:
                root,pre,pst = plist[-1],[],[]
                #找出左右子树的分裂点
                for i in range(len(plist)-1):
                    if plist[i]>root:
                        break
                #处理右子树为空的情况
                if i == len(plist)-2:
                    i+=1
                pre = plist[:i]
                pst = plist[i:-1]
                #判断右子树是否满足条件
                if len(pst)!=0:
                    for i in pst:
                        if i<root:
                            flag = 0
                #print(plist,pre,pst,flag,root)
                #递归判断
                judge(pre)
                judge(pst)
        judge(postorder)
        return True if flag ==1 else False
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值