剑指offer-题目-思路-python实现51-60

目录

51.构建乘积数组

52.正则表达式匹配

53.表示数值的字符串

54.字符流中第一个不重复的字符

55.链表中环的入口节点

56.删除链表中重复的结点

57.二叉树的下一个结点

58.对称的二叉树

59.把二叉树打印成多行

60.按之字形顺序打印二叉树


51.构建乘积数组

给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素
B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。不能使用除法。

先求前向乘积列表t_forword=a[0]*a[1]*...*a[i-1];存入b
再求后项乘积列表t_back=a[len(a)-1]*a[len(a)-1]*...*a[i+1];b[i]*t_back得到最后结果

class Solution:
    def multiplyArr(self,a):
        b=[1]*len(a)
        #前向乘积a[0]*a[1]...a[i-1]
        t_forward=1
        for i in range(1,len(a),1):
            t_forward*=a[i-1]
            b[i]=t_forward
            
        #后项乘积获取a[len(a)-1]*a[len(a)-1]*...*a[i+1]
        t_back=1
        for i in range(len(a)-1,-1,-1):
            b[i]*=t_back
            t_back*=a[i]
        
        return b
    
    def valid(self,a):
        t=1
        b=[]
        for i in a:
            t*=i
        
        for i in a:
            b.append(t/i)
        return b
            
            

s=Solution()
a=[1,2,3,4,5]
r1=s.multiplyArr(a)
r2=s.valid(a)
print(r1,r2)

52.正则表达式匹配

请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,
而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配
整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配。

思路:递归匹配f(s,p),s字符串,p模式
1、当p的第二个字符p[1]不是*时:(1)如果s[0]与p[0]相匹配,那么s和p均后移一位,匹配剩余的f(s-1,p-1);
  (2)如果字符串第一个字符和模式中的第一个字符相不匹配,直接返回false。
2、当p的第二个字符p[1]是*时:如果s[0]与p[0]相匹配:
  (1)字符串后移1位,模式后移2字符。
   (2)字符串后移1位,模式不变,相当于x*中的x出现多次;
   如果s[0]与p[0]不匹配:字符串不变,模式后移2字符,相当于x*中的x出现0次;
3、当s和p均为0时,匹配成功返回;如果其中一个不为0,匹配失败

class Solution:
    def match(self,s,p):
        if len(s)==0 and len(p)==0:
            return True
        if (len(s)!=0 and len(p)==0) or (len(s)==0 and len(p)!=0):
            return False
        
        if len(p)>1 and p[1]=='*':
            if (p[0]==s[0] or p[0]=='.'):
                return self.match(s[1:],p[2:]) or self.match(s[1:],p)
            else:
                return self.match(s,p[2:])
        else:
            if (p[0]==s[0] or p[0]=='.'):
                return self.match(s[1:],p[1:])
            else:
                return False
        
            
a="aaab"
p="ab*ac*a"  
s=Solution()
r=s.match(a,p)
print(r)          

53.表示数值的字符串

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123",
"3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。

思路:重点需要考察的是
1)是否有符号;符号只可能出现在开头和eE的后面 
2)是否有. ; .只能出现一次,不能在eE附近,不能在eE后面,且前后必须为数字
3)是否有eE;  e或E只能出现一次且不能在开头和末尾,前面只能是数字,后面只能是"+-0123456789"
4)是否在"0123456789"之间

class Solution:
    def isNumStr(self,s):
        hasDot=True
        hasE=True
        
        for i in range(len(s)):
            if(s[i] in "+-" and (i==0 or (i<=len(s)-1 and s[i-1] in "Ee") ) ):
                continue
            
            elif hasDot and  s[i]=='.':
                hasDot=False
                if i>=len(s)-1 or s[i+1] not in "0123456789":
                    return False
            
            elif hasE and s[i] in 'eE':
                hasDot=False
                hasE=False
                if (i==0 or i>=len(s)-1) or (s[i-1] not in "0123456789") or (s[i+1] not in "+-0123456789"):
                    return False
            elif s[i] not in "0123456789":
                return False
        
        return True

s=Solution()
r=s.isNumStr("-123.123e-10")
print(r)

54.字符流中第一个不重复的字符

请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,
第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。

思路:声明一个字典记录每个字符出现的次数,遍历字符串,如果第一次出现次数为1的,则返回

class Solution:
    def findAppearOnce(self,s):
        char_num={}
        for c in s:
            if c not in char_num.keys():
                char_num[c]=1
            else:
                char_num[c]+=1
        for c in s:
            if char_num[c]==1:
                return c
        return None

s=Solution()
r=s.findappearOnce("google")
print(r)

55.链表中环的入口节点

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

思路:快慢指针,快指针走两步,慢指针走一步;当快指针fast与low指针相遇时,及找到了循环链表的入口

class Node:
    def __init__(self,val):
        self.val=val
        self.next=None
        
class Solution:
    def findEntryNodeOfLoop(self,head):
        if head ==None or head.next==None or head.next.next==None:
            return None
        
        fast=head.next.next
        low=head.next
        
        while fast and low:
            if fast==low:
                return fast
            
            if fast.next==None or fast.next.next==None:
                return None
            fast=fast.next.next
            low=low.next
        
        return None

56.删除链表中重复的结点

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。
 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5。(leetcode82)
 
 思路:1、因为是排序链表,重复的数都是挨着的,遍历一遍链表删除重复的数据

class Node:
    def __init__(self,val):
        self.val=val
        self.next=None

class Solution:
    def deleteDuplicatedNode(self,head):
        dupli=Node(-1)   #避免第一个节点就是重复节点
        dupli.next=head 
        
        cur=head
        last=dupli
        
        while cur and cur.next:
            if cur.val==cur.next.val:
                val=cur.val
                while cur and val==cur.val:
                    cur=cur.next
                last.next=cur
            else:
                last=cur
                cur=cur.next
            
        return dupli.next

    
a = Node(1)
b = Node(2)
c = Node(2)
d = Node(5)
e = Node(6)
f = Node(6)


a.next = b
b.next = c
c.next = d
d.next = e
e.next = f

s=Solution()
res = s.deleteDuplicatedNode(a)

cur = res
while cur:
    print(cur.val)
    cur = cur.next

57.二叉树的下一个结点

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

给定二叉树: 
    3
   / \
  9  20
    /  \
   15   7 

思路:
1、如果该节点有右子树,那么它的下一个节点就是它的右子树的最左侧子节点;

2、如果该节点没有右子树且是父节点的左子树,那么下一节点就是父节点;

3、如果该节点没有右子树且是父节点的右子树,比如i节点,那么我们往上找父节点,找到一个节点满足:
 它是它的父节点的左子树的节点。

class TreeNode:
    def __init__(self,val):
        self.val=val
        self.left=None
        self.right=None
        self.parent=None

class Solution:
    def findNext(self,root,p):
        if root==None:
            return None
        
        if p.right:
            res=p.right
            while res.left:
                res=res.left
        else:            
            while p.parent:
                res=p.parent
                if res.left==p:
                    return res
                p=p.parent
        
        return res
    

a = TreeNode(3)
b = TreeNode(9)
d = TreeNode(20)
e = TreeNode(15)
f = TreeNode(7)

a.left, a.right = b, d
b.parent,d.parent=a,a
d.left, d.right = e,f
e.parent,f.parent=d,d

s=Solution()
res = s.findNext(a,b)
print(res.val)    

58.对称的二叉树

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

思路:递归地判断左右子树是否对称;递归结束条件,左右子树都为空,返回True,仅仅left或right为空
或左右子树的值不相等,返回False

class TreeNode:
    def __init__(self,val):
        self.val=val
        self.left=None
        self.right=None

class Solution:
    def isSymmertrical(self,root):
        if root==None:
            return True
        return self.ismirror(root.left,root.right)
    
    def ismirror(self,left,right):
        if left==None and right==None:
            return True
        if left==None or right==None or left.val!=right.val:
            return False
        return self.ismirror(left.left,right.right) and self.ismirror(left.right,right.left)


a = TreeNode(3)
b = TreeNode(9)
d = TreeNode(20)
e = TreeNode(15)
f = TreeNode(7)

a.left, a.right = b, d
d.left, d.right = e,f

s=Solution()
res = s.isSymmertrical(a)
print(res)      

59.把二叉树打印成多行

从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。(leetcode102题)

给定二叉树: 
    3
   / \
  9  20
 /  /  \
 6 15   7    
返回其层次遍历结果:
[
  [3],
  [9,20],
  [6,15,7]
]

思路:层次遍历二叉树;1、申请一队列q,存储当前层次节点;2、循环遍历队列q,pop开头节点cur,并
将cur.val结果存入列表t;3、将每层结果列表t存入最终结果res,循环2直到q为空

class TreeNode:
    def __init__(self,val):
        self.val=val
        self.left=None
        self.right=None
        
class Solution:
    def printTreeRow(self,root):
        q=[root]
        res=[]
        while q:
            t=[]
            cur_level_nodes=len(q)
            for i in range(cur_level_nodes):
                cur=q.pop(0)
                t.append(cur.val)
                if cur.left:
                    q.append(cur.left)
                if cur.right:
                    q.append(cur.right)
            res.append(t)
        return res
    
a = TreeNode(3)
b = TreeNode(9)
c=TreeNode(6)
d = TreeNode(20)
e = TreeNode(15)
f = TreeNode(7)

a.left, a.right = b, d
d.left, d.right = e,f
b.left=c

s=Solution()
res = s.printTreeRow(a)
print(res)
    

60.按之字形顺序打印二叉树

请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,
第三行按照从左到右的顺序打印,其他行以此类推。

给定二叉树: 
    3
   / \
  9  20
 /  /  \
 6 15   7    
返回其层次遍历结果:
[
  [3],
  [20,9],
  [6,15,7]
]
思路:层次遍历二叉树;1、申请一队列q,存储当前层次节点;2、循环遍历队列q,pop开头节点cur,并
将cur.val结果存入列表t; 3、如果是单行将每层结果列表t存入res,如果是双行,将t的反转存到res,
循环2直到q为空

class TreeNode:
    def __init__(self,val):
        self.val=val
        self.left=None
        self.right=None

class Solution:
    def printTreeRowZ(self,root):
        q=[root]
        res=[]
        flag=True #标识单层还是双层
        
        while q:
            t=[]
            cur_level_nodes=len(q)
            for i in range(cur_level_nodes):
                cur=q.pop(0)
                t.append(cur.val)
                if cur.left:
                    q.append(cur.left)
                if cur.right:
                    q.append(cur.right)
            if flag:
                res.append(t)
                flag=False
            else:
                res.append(t[::-1])
                flag=True
        return res

a = TreeNode(3)
b = TreeNode(9)
c=TreeNode(6)
d = TreeNode(20)
e = TreeNode(15)
f = TreeNode(7)

a.left, a.right = b, d
d.left, d.right = e,f
b.left=c

s=Solution()
res = s.printTreeRowZ(a)
print(res)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值