牛客网刷题8(python)

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]。不能使用除法。

思路:

B[0] = A[1] * A[2] * A[3] * A[4] *....*A[n-1] ;(没有A[0])

B[1 ]= A[0] * A[2] * A[3] * A[4] *....*A[n-1] ;(没有A[1])

B[2] = A[0] * A[1] * A[3] * A[4] *....*A[n-1] ;(没有A[2])

class Solution:
    def multiply(self, A):
        # write code here
        B = A[:]
        for m in range(len(A)):
            sum = 1
            for n in range(len(A)):
                if n != m:
                    sum = sum*A[n]
                B[m] = sum
        return B

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

思路:

当模式中的第二个字符不是“*”时:

1、如果字符串第一个字符和模式中的第一个字符相匹配,那么字符串和模式都后移一个字符,然后匹配剩余的。

2、如果 字符串第一个字符和模式中的第一个字符相不匹配,直接返回false。

而当模式中的第二个字符是“*”时:

如果字符串第一个字符跟模式第一个字符不匹配,则模式后移2个字符,继续匹配。如果字符串第一个字符跟模式第一个字符匹配,可以有3种匹配方式:

1、模式后移2字符,相当于x*被忽略;

2、字符串后移1字符,模式后移2字符;

3、字符串后移1字符,模式不变,即继续匹配字符下一位,因为*可以匹配多位;

# -*- coding:utf-8 -*-
class Solution:
    # s, pattern都是字符串
    def match(self, s, pattern):
        # write code here
        if (len(s) == 0 and len(pattern) == 0):
            return True
        if (len(s) > 0 and len(pattern) == 0):
            return False
        if (len(pattern) > 1 and pattern[1] == '*'):
            if (len(s) > 0 and (s[0] == pattern[0] or pattern[0] == '.')):
                return (self.match(s, pattern[2:]) or self.match(s[1:], pattern[2:]) or self.match(s[1:], pattern))
            else:
                return self.match(s, pattern[2:])
        if (len(s) > 0 and (pattern[0] == '.' or pattern[0] == s[0])):
            return self.match(s[1:], pattern[1:])
        return False

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

方法1:笔试做法。

class Solution:
    # s字符串
    def isNumeric(self, s):
        # write code here
        try:
            L = float(s)
            return True
        except:
            return False
            

方法2:循环判断,思路:

  • 12e说明e的后面必须有数字,不能有两个e
  • +-5说明符号位要么出现一次在首位,要么出现一次在e的后一位,其他地方都不能有
  • 12e4.3说明e的后面不能有小数,1.2.3说明不能有两个小数点
  • 1a3.14说明不能有其他的非法字符,比如这里的a
# -*- coding:utf-8 -*-
class Solution:
    # s字符串
    def isNumeric(self, s):
        # write code here
        n = len(s)
        if n==0:
            return False
        type = 0
        for i in range(n):
            #print s[i]
            if s[i]=="+" or s[i]=="-":
                if i==n-1:#正负号后面没数字了
                    return False
                elif i==0:
                    type = 1#整型
                elif type==3:
                    continue
                else:
                    return False
            elif s[i]=="E" or s[i]=="e":
                if (type==1 or type==2) and i!=n-1:#E/e后面不能没有数字
                    type = 3
                else:
                    return False
            elif s[i]==".":
                if type==1 or type==0 and i!=n-1:
                    type = 2
                else:
                    return False
            elif "0"<=s[i]<="9":
                if i==0:
                    type=1
                continue
            else:
                return False
        return True

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

# -*- coding:utf-8 -*-
class Solution:
    # 返回对应char
    def __init__(self):
        self.s = ''
        self.dict = {}
    def FirstAppearingOnce(self):
        # write code here
        for i in self.s:
            if self.dict[i] == 1:
                return i
        return '#'
    def Insert(self, char):
        # write code here
        self.s += char
        if char in self.dict:
            self.dict[char] += 1
        else:
            self.dict[char] = 1
        

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

思路:遍历链表,环的存在,遍历遇见的第一个重复的即为入口节点。

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def EntryNodeOfLoop(self, pHead):
        # write code here
        temp = []
        p = pHead
        while p:
            if p in temp:
                return p
            else:
                temp.append(p)
            p = p.next

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

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def deleteDuplication(self, pHead):
        # write code here
        if pHead is None or pHead.next is None:
            return pHead
        head1 = pHead.next
        if head1.val != pHead.val:
            pHead.next = self.deleteDuplication(pHead.next)
        else:
            while head1.val == pHead.val and head1.next is not None:
                head1 = head1.next
            if head1.val != pHead.val:
                #注意此处是pHead而不是pHead1,目的是删除重复出现的结点,一个不留
                pHead = self.deleteDuplication(head1)
            else:
                return None
        return pHead

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

思路:二叉树的中序遍历为左根右,方式为递归。若要找下一个结点,有三种情况。

1.二叉树为空,则返回空;

2.节点右孩子存在,则设置一个指针从该节点的右孩子出发,一直沿着指向左子结点的指针找到的叶子节点即为下一个节点;

3.节点不是根节点。如果该节点是其父节点的左孩子,则返回父节点;否则继续向上遍历其父节点的父节点,重复之前的判断,返回结果。

-*- coding:utf-8 -*-
class TreeLinkNode:
    def __init__(self, x):
        self.val = x
        self.left = None    
        self.right = None
        self.next = None
class Solution:
    def GetNext(self, pNode):
        # write code here
        if not pNode:
            return pNode
        if pNode.right:
            left1 = pNode.right
            while left1.left:
                left1 = left1.left
            return left1
        else:
            while pNode.next:
                temp = pNode.next
                if temp.left == pNode:
                    return temp
                pNode = temp
                

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

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def isSymmetrical(self, pRoot):
        # write code here
        def is_Same(p1, p2):
            if not p1 and not p2:
                return True
            if p1 and p2:
                if p1.val==p2.val:
                    return is_Same(p1.left, p2.right) and is_Same(p1.right, p2.left)
                return False
            return False
        if not pRoot:
            return True
        if pRoot.left and not pRoot.right:
            return False
        if pRoot.right and not pRoot.left:
            return False
        return is_Same(pRoot.left, pRoot.right)

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

#利用双队列实现

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
from collections import deque
class Solution:
    def Print(self, pRoot):
        if not pRoot:
            return []
        result = []
        tmp = []
        last = pRoot #记录每层的最后一个结点,方便层序遍历换行
        left_to_right = True
        next_level_node_LtoR = deque([pRoot]) #初始化下一层所有节点的队列,起初为只有根结点
        while next_level_node_LtoR: #当下一层不为空时
            current_node = next_level_node_LtoR.popleft() #不停从下层队列左边弹出
            tmp.append(current_node.val) #将弹出结点放入tmp中
            if current_node.left:
                next_level_node_LtoR.append(current_node.left)
            if current_node.right:
                next_level_node_LtoR.append(current_node.right)
            if current_node == last: #当运行到最后一个结点,给result赋值当前行的所有元素,也就是tmp
                if left_to_right:
                    result.append(tmp)
                else: #若该行应该为从右到左,则倒序append
                    result.append(tmp[::-1])
                tmp = [] #清空tmp,以便下一层继续使用
                left_to_right = not left_to_right #调整此项,颠倒下一行的输出顺序
                if next_level_node_LtoR: #更新下一行的last结点,如果下一行已经没有元素就会退出
                    last = next_level_node_LtoR[-1]
        return result

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

思路:

按层次输出二叉树

 * 访问根节点,并将根节点入队。

 * 当队列不空的时候,重复以下操作。

 * 1、弹出一个元素。作为当前的根节点。

 * 2、如果根节点有左孩子,访问左孩子,并将左孩子入队。

 * 3、如果根节点有右孩子,访问右孩子,并将右孩子入队。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回二维列表[[1,2],[4,5]]
    def Print(self, pRoot):
        # write code here
        if not pRoot:
            return []
        nodestack = [pRoot]
        result = []
        while nodestack:
            res = []
            nextstack = []
            for i in nodestack:
                res.append(i.val)
                if i.left:
                    nextstack.append(i.left)
                if i.right:
                    nextstack.append(i.right)
            nodestack = nextstack
            result.append(res)
        return result
                
        

61.请实现两个函数,分别用来序列化和反序列化二叉树

分析:

    1.序列化是指通过前序遍历把二叉树变成数组

    2.反序列化是指重建二叉树

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    flag = -1
    def Serialize(self, root):
        # write code here
        if not root:
            return '#'
        return str(root.val) + ',' + self.Serialize(root.left) + ',' + self.Serialize(root.right)
     
    def Deserialize(self, s):
        # write code here
        self.flag += 1
         
        l = s.split(',')
        if self.flag >= len(s):
            return None
         
        root = None
        if l[self.flag] != '#':
            root = TreeNode(int(l[self.flag]))
            root.left = self.Deserialize(s)
            root.right = self.Deserialize(s)
        return root
        

62.给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8)    中,按结点数值大小顺序第三小结点的值为4。

分析:对二叉搜索树中序遍历便能得到排序数组,然后按顺序输出数组中的第k个数即可。

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

class Solution:
    def KthNode(self, pRoot, k):
        if not pRoot or k == 0:
            return None
        n = self.isorder(pRoot)
        if k > len(n):
            return None
        return n[k-1]

    def isorder(self, pRoot):
        res = []
        if not pRoot:
            return None
        if pRoot.left:
            res.extend(self.isorder(pRoot.left))  #注意列表里添加列表用extend
        res.append(pRoot)                         #列表里添加元素用append
        if pRoot.right:
            res.extend(self.isorder(pRoot.right))
    return res

63.如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.data = []
    def Insert(self, num):
        # write code here
        self.data.append(num)
        self.data.sort()
    def GetMedian(self,data):
        # write code here
        l = len(self.data)
        if l%2 == 0:
            return (self.data[l//2]+self.data[l//2-1])/2.0
        else:
            return self.data[int(l//2)]

64.给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。

# -*- coding:utf-8 -*-
class Solution:
    def maxInWindows(self, num, size):
        # write code here
        if len(num) < size or size == 0:
            return []
        temp = []
        for i in range(len(num)-size+1):
            temp.append(max(num[i:i+size]))
        return temp
            

65.请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。

分析:这是回溯法的典型例子。

由于路径不能重复进入矩阵的格子,还需要定义和字符矩阵大小一样的布尔值矩阵,用来标识路径是否已经进入每个格子。 当矩阵中坐标为(row,col)的格子和路径字符串中相应的字符一样时,从4个相邻的格子(row,col-1),(row-1,col),(row,col+1)以及(row+1,col)中去定位路径字符串中下一个字符。

如果4个相邻的格子都没有匹配字符串中下一个的字符,表明当前路径字符串中字符在矩阵中的定位不正确,我们需要回到前一个,然后重新定位。一直重复这个过程,直到路径字符串上所有字符都在矩阵中找到合适的位置。

class Solution:
    def hasPath(self, matrix, rows, cols, path):
        for i in range(rows):
            for j in range(cols):
                if matrix[i*cols+j] == path[0]:
                    if self.findPath(list(matrix), rows, cols, path[1:], i ,j)
                        return True
        return False

    def findPath(self,  matrix, rows, cols, path , i, j):
        if not path:
            return True
        matrix[i*cols+j] = '#'  #将已经遍历的点作标记
        if j+1<cols and matrix[i*cols+j+1]==path[0]:
            return self.find(matrix,rows,cols,path[1:],i,j+1)
        elif j-1>=0 and matrix[i*cols+j-1]==path[0]:
            return self.find(matrix,rows,cols,path[1:],i,j-1)
        elif i+1<rows and matrix[(i+1)*cols+j]==path[0]:
            return self.find(matrix,rows,cols,path[1:],i+1,j)
        elif i-1>=0 and matrix[(i-1)*cols+j]==path[0]:
            return self.find(matrix,rows,cols,path[1:],i-1,j)
        else:
            return False
                

66.地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?

思路:使用回溯法,将地图全部置1,遍历能够到达的点,将遍历的点置0并令计数+1.

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.count = 0
    def movingCount(self, threshold, rows, cols):
        # write code here
        arr = [[1 for i in range(cols)] for j in range(rows)]
        self.findway(arr, 0 ,0 ,threshold)
        return self.count
    
    def findway(self, arr, i, j, k):
        if i<0 or j<0 or i>=len(arr) or j>=len(arr[0]):
            return 
        tempi = list(map(int, list(str(i))))
        tempj = list(map(int, list(str(j))))
        if sum(tempi)+sum(tempj) >k or arr[i][j] != 1:
            return 
        arr[i][j] = 0
        self.count += 1
        self.findway(arr, i+1, j ,k)
        self.findway(arr, i - 1, j, k)
        self.findway(arr, i, j + 1, k)
        self.findway(arr, i, j - 1, k)

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值