剑指offer编程66题详解 python版

事先约定:由于涉及到二叉树的题无法直接测试对错(二叉树无法像列表那样给出),所以需要先直接定义个二叉树,结构按具体需求就好,我的具体方法如下

比如现在按实际需求,我需要如下的这样一个二叉搜索树结构:

那么如下是具体的构造方式: 

class TreeNode(object):
    def __init__(self,item):
        self.data = item
        self.lchild = None
        self.rchild = None

class Solution(object):
    def __init__(self):
        self.root = None

    '按层次遍历建立二叉树,但得到的不是二叉搜索树,需要根据实际需求,按位置添加,None做补位'
    def add(self, item):
        node = TreeNode(item)
        'bool([])==False, bool([None])==True'
        if self.root == None:  # 当根节点None,[self.root]即[None]
            self.root = node
            return
        queue = [self.root]  # 二叉树以list形式存储
        while queue:  # 从根开始,依次往下检查各节点,直至全取出
            cur = queue.pop(0)  # 每轮把list现有的首节点取出
            if not cur.lchild:
                cur.lchild = node
                return
            else:
                queue.append(cur.lchild)
            if not cur.rchild:
                cur.rchild = node
                return
            else:
                queue.append(cur.rchild)

    def breadth_travel(self):  # 层次遍历
        'bool([])==False, bool([None])==True'
        if self.root == None:  # 当根节点None,[self.root]即[None]
            return
        queue = [self.root]  # 二叉树以list形式存储
        while queue:  # 从根开始,依次往下检查各节点,直至全取出
            cur = queue.pop(0)  # 每轮把list现有的首节点取出
            print(cur.data, end=' ')
            if cur.lchild:
                queue.append(cur.lchild)
            if cur.rchild:
                queue.append(cur.rchild)

    def preorder(self, node):  # 前序遍历
        if not node:
            return
        print(node.data, end=' ')
        self.preorder(node.lchild)
        self.preorder(node.rchild)

    def inorder(self, node):  # 中序遍历
        if not node:
            return
        self.inorder(node.lchild)
        print(node.data, end=' ')
        self.inorder(node.rchild)

    def postorder(self, node):  # 后序遍历
        if not node:
            return
        self.postorder(node.lchild)
        self.postorder(node.rchild)
        print(node.data, end=' ')

if __name__ == '__main__':
    s = Solution()
    """
    因为我是按层次遍历添加的,左右子树不该有节点的地方用None补位了,故得到结果比如中序时,忽略结果里的None即可
    """
    s.add(59)
    s.add(58)
    s.add(80)
    s.add(27)
    s.add(None)
    s.add(73)
    s.add(86)
    s.add(3)
    s.add(49)
    s.breadth_travel()
    print('')
    s.inorder(s.root)
    print('')
    s.postorder(s.root)
    print('')

得到如下: 

 

1 .题目描述:在一个二维数组中(每个一维数组的长度相同),每一行都按照从到右递增的顺序排列,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
解析:由于每行从左到右递增,每列从上到下递增,因此每列的最后一个元素最大;函数可以从每行的最后一个元素 A 开始判断,如果目标 B 大于 A,则从下一行最后一个元素开始判断,如果 B 小于 A,则往前移一列,从新列开始判断

def Find(target, arr):
    row = len(arr)
    col = len(arr[0])
    i = 0#首行,向下加
    j = col - 1#末列,向前减
    while i<row and j>-1:
        if arr[i][j] < target:
            i += 1
        elif arr[i][j] > target:
            j -= 1
        else:
            return 'T'
    return 'F'

2.请实现一个函数,将一个字符串中的每个空格替换成”%20”。例如,当字符串为 We Are Happy 则经过替换之后的字符串为 We%20Are%20Happy 

解析:没啥可说的,就是一个替换函数

def f(s):
    return s.replace(' ','%20')
print(f('We Are Happy'))

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

解析:List.insert(0,Node.data)#每次读到的链值都当道list队首,即实现从尾到头来得到list

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

def F(Node):
    List = []
    while Node:
        List.insert(0,Node.data)#每次读到的链值都当道list队首,即实现从尾到头来得到list
        Node = Node.next
    return List

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

解析:递归

class TreeNode(object):
    def __init__(self,data):
        self.data = data
        self.lchild = None
        self.rchild = None

class Solution(object):
    def reConstructBinaryTree(self,pre,tin):#pre前序,tin中序
        '前序的首元素是根节点,不超一个则直接得结果,否则递归下去'
        if len(pre) == 0:
            return None
        elif len(pre) == 1:
            return TreeNode(pre[0])
        else:
            node = TreeNode(pre[0])#现节点
            node_id = tin.index(node.data)
            node.lchild = self.reConstructBinaryTree(pre[1: node_id+1],
                                                tin[:node_id])#tin.index(pre[0])先序根节点pre[0]在中序tin的索引
            node.rchild = self.reConstructBinaryTree(pre[node_id+1:],
                                                tin[node_id+1:])
            return node

5.用两个栈来实现一个队列,完成队列的 Push 和 Pop 操作。队列中的元素为 int类型

解析:见代码

class Solution(object):
    def __init__(self):
        self.stackA = []
        self.stackB = []

    def Push(self,node):
        self.stackA.append(node)#用栈A做入队

    """
    栈B做出队时,若空则需先把A的元素全都append()到B里,再pop()
    """
    def Pop(self):
        if self.stackB:
            self.stackB.pop()
        else:
            while self.stackA:
                self.stackB.append(self.stackA.pop())
            return self.stackB.pop()

s = Solution()
s.Push(11)
print(s.Pop())

6. 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3, 4, 5, 1, 2}为{1, 2,3, 4, 5}的一个旋转,该数组的最小值为 1。NOTE: 给出的所有元素都大于 0,若数组大小为0,请返回 0.

解析:输入的是旋转后的数组,找到其中min值对应的索引,然后做尾与首的拼接。则得到的就是原数组,由于是非减排序,则原数组的首元素就是min值

def minNum_RotateArray(rotateArray):#输入的是旋转后的数组,输出的是这个旋转后的数组的min
    if len(rotateArray)==0:
        return 0
    else:
        min_num = min(rotateArray)
        # return  min_num
        min_idx = rotateArray.index(min_num)
        # return min_idx
        newArray = rotateArray[min_idx:] + rotateArray[:min_idx]
        return newArray,newArray[0]

print(minNum_RotateArray([11,55,88,9,11]))

7.大家都知道斐波那契数列,现在要求输入一个整数 n,请你输出斐波那契数列的第 n 项(从 0 开始,第 0 项为 0).  n<=39

解析:斐波那契就是后项是前两项的和,第一二项都是1.

def F(n):#后项是前两项之和
    a1 = 0
    a2 = 1
    if n <=  0:
        return 0
    elif n > 39:
        return 'Error'
    else:
        for _ in range(n):
            a2,a1 = a1,a1+a2
        return a2

print(F(12))

8.一只青蛙一次可以跳上 1 级台阶,也可以跳上 2 级。求该青蛙跳上一个 n 级的台阶总共有多少种跳法(先后次序不同算不同的结果)

解析:把n级台阶时的跳法记为f(n),当n>2时,第一次跳的时候有两种不同的选择:一是第一次只跳1级,此时跳法数目等于后面剩下的n-1级台阶的跳法数目,即为f(n-1);另外一种是第一次跳2级,此时跳法数目等于后面剩下的n-2级台阶的跳法数目,即为f(n-2);因此n级台阶时的跳法为f(n)=f(n-1)+f(n-2)。不难看出这实际是斐波拉契数列的变形应用,把斐波拉契数列的每一项向前移动了1位。

def JumpFloor(n):
    a,b = 0,1
    if n == 0:
        return 0
    else:
        for _ in range(n):
            a,b = b,a+b
        return b #f(n)=f(n-1)+f(n-2)

注:①

 

9.一只青蛙一次可以跳上 1 级台阶,也可以跳上 2 级......它也可以跳上 n 级。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。

解析:考虑这样的一种情况,青蛙最后一跳跳到最后台阶,这样的每一跳都是一种独立的方法,因此,青蛙可以从 n‐1 台阶跳一次,也可以从 n‐2 台阶跳两次,依次类推,则每次跳的方案有 f(n‐1), f(n‐2), ... f(1)种,此时 f(n) = f(n‐1)+ f(n‐2) + f(n‐3) + ... + f(1), 可以推出 f(n) =2f(n‐1).

def JumpFloor(n):
   count = 1
   if n == 1:
       return 1
   else:
       for _ in range(n-1):
           count = count*2
           return count #f(n)=2*f(n-1)

10.我们可以用 2 * 1 的小矩形横着或者竖着去覆盖更大的矩形。请问用 n 个 2 *1 的小矩形无重叠地覆盖一个 2 * n 的大矩形,总共用多少种方法?

解析:对于矩形的覆盖,可以考虑最后的覆盖是横着还是竖着的小矩形,如果是竖着(占一列),则有 f(n‐1)种覆盖方法,如果是横着(占两行),则有 f(n‐2) 种覆盖方法,因此一共有 f(n)= f(n‐1) + f(n‐2)种覆盖方法

由穷举也可见,是斐波那契数列问题(数列前两项都是1,从第3项开始,每一项都等于前两项之和,即 f(n)= f(n‐1) + f(n‐2))。

def rectCover(n):
    if n == 0:
        return 0
    a,b = 1,1
    for _ in range(n):
        a,b = b,a+b
    return a #斐波那契数列f(n)=f(n-1)+f(n-2)

 

11.输入一个整数,输出该数二进制表示中 1 的个数。其中负数用补码表示。

解析:用移位运算n>>i . 在 Python 中 int 型整数是用 32 位二进制代码存储的,负数按照补码的形式存储的,因此可以将该整数的 32 位二进制代码,一位一位的与 1 做‘&’运算,运算结果的和便是1的个数

def NumOf1(n):
    count = 0
    for i in range(32):
        count = count + ((n>>1) & 1)
    return count

12.给定一个 double 类型的浮点数 base 和 int 类型的整数 exponent。求 base 的exponent 次方。

解析:先考虑base与exponent为0的情况,其次是exponent为负时,得到的是result的倒数

def F(base,exponent):
    result = 1
    if base == 0:
        return 0
    elif exponent == 0:
        return 1
    else:
        for i in range(abs(exponent)):
            result = result*base
        if exponent > 0:
            return result
        else:
            return 1/result
print(F(3.0, 4))

13.输入一个整数数组,实现一个函数来调用该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

解析:判断数组的每个元素,奇数的放到一个list,偶数的放到另个list,最后前后拼接

def F(array):
    a = []
    b = []
    for i in array:
        if i%2 == 1:
            a.append(i)
        else:
            b.append(i)
    return a+b #列表拼接
import numpy as np
print(F(np.array([1,2,3,4,5,6,7,8,9])))

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

解析:把输入的链表的每个元素append()到空list,则list[-k]即是

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

def F(node,k):
    LinkList = []
    while node:
        LinkList.append(node)
        node = node.next
    if k>len(LinkList) or k<1:#没倒数第0个的说法
        return None
    return LinkList[-k]

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

解析:链表的反转 等价于反转链表的指针,只要把原链表中的指针反转,便是链表的反转
比如 原链表中 head指向head.next,先把head.next保存起来(不然改变head的指向后,原链表会断开,找不到下一个节点),然后改变head指向result(新建节点),再用result表示新链表的表头
1>2>3>4
1(result) 2>3>4
1<2(result) 3>4
1<2<3(result) 4
1<2<3<4(result)
 

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

def ReverseNode(item):
    node = Node(item)
    if not node or not node.next:
        return node
    last = None#新链表
    while node:
        tmp = node.next#将下一步的地址暂存到tmp
        node.next = last#把当前节点node与temp截断,并将node指向新链表last
        last = node  # 将node的地址指向给新链表
        node = tmp  # 将node原来的下一步tmp指向给node,循环下去,从而一个个节点改变指向
    return last

 

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

解析:从头开始比较两个链表元素的大小,将元素小的结点插入到新的链表中

(1).递归

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

def Merge(data1,data2):
    node1 = Node(data1)
    node2 = Node(data2)
    if node1 == None:#None没有data属性
        return node2
    if node2 == None:
        return node1
    merge = None
    if node1.data < node2.data:
        merge = node1#小的元素放到新链表
        merge.next = Merge(node1.next, node2)
    else:
        merge = node2
        merge.next = Merge(node1,node2.next)
    return merge

(2) .非递归(待验证)

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

def Merge(data1,data2):
    node1 = Node(data1)
    node2 = Node(data2)
    merge = Node(90)
    while node1 and node2:
        if node1.data > node2.data:
            merge.next = node2
            node2 = node2.next
        else:
            merge.next = node1
            node1 = node1.next
        merge = merge.next
    if node1:#链2先完
        merge.next = node1
    elif node2:
        merge.next = node2
    return merge

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

解析:遍历二叉树A,定位B的根节点在A中的可能位置——> 定位后,验证B是不是A当前位置的子结构

18.操作给的定的二叉树,将其变换为源二叉树的镜像

解析:a=b, b=a

class TreeNode(object):
    def __init__(self,data):
        self.data = data
        self.lchild = None
        self.rchild = None

def Mirror(root):
    rootNode = TreeNode(root)
    if rootNode == None:
        return rootNode
    else:
        """
        node = rootNode.lchild
        rootNode.lchild = rootNode.rchild
        rootNode.rchild = node
        """
        rootNode.rchild, rootNode.lchild = rootNode.lchild, rootNode.rchild #python中的交换直接就是地址的交换
        Mirror(rootNode.rchild)
        Mirror(rootNode.lchild)
        return rootNode

注:

 

19. 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下 4 X 4 矩阵:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

解析:顺时针输出可以看成先输出矩阵的第一行(输出后删除该行),然后将矩阵逆时针旋转90 度,又是一个新的矩阵,再输入第一行即可,依次直到矩阵为空为止

class Solution(object):
    def PrintMatrix(self,matrix):
        result = []
        while(matrix):
            result += matrix.pop(0)#矩阵二维,matrix.pop(0)是矩阵的首行
            if not matrix:
                break
            matrix = self.turn(matrix)#每pop出首行,便对matrix逆时针旋转90度
        return result

    def turn(self,matrix):#matrix逆时针旋转90度
        num_r = len(matrix)#行数        
        num_c = len(matrix[0])#列数        
        newmat = []#放新的矩阵
        
        for i in range(num_c):
            newmat2 = []  #放新的每一行
            for j in range(num_r):
                newmat2.append(matrix[j][i])
            newmat.append(newmat2)
        newmat.reverse()
        return newmat

注:

①reverse()是python中列表的一个内置方法(也就是说,在字典,字符串或者元组中,是没有这个内置方法的),用于列表中数据的反转:

例: 

②实现矩阵的逆时针旋转90度

20.定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min 函数 (时间复杂度应为 O(1))

解析:由于要求时间复杂度为 1,因此借助一个辅助栈, 栈顶用来存储栈中的最小元素。使用双栈实现。一个数据栈data,一个最小栈min.数据栈存正常入栈的元素,最小栈永远存数据栈中当前最小值。具体是依靠以下规则来实现的。入栈时无论如何先给数据栈入栈,而此时看入栈的元素与最小栈栈顶元素的大小,如果该元素小于等于最小栈栈顶元素,就将该元素也给最小栈入栈,否则说明要入栈的元素大于当前最小栈的栈顶元素,则不用更新当前最小栈栈顶元素,因此为了保持与数据栈的元素个数相等,最小栈将其栈顶元素再入一次,表明此时最小元素还是原来的数据;出栈时两个栈同时出,因为要保持数据个数一致,当要找当前最小元素时,直接从最小栈的栈顶弹出元素即可。

例:

 

(此处以方法2为例)

class Solution(object):
    def __init__(self):
        self.stack = []
        self.mini_element = []

    def Push(self,node):
        self.stack.append(node)#stack正常逐一入栈
        if not self.mini_element:
            self.mini_element.append(node)
        else:
            if self.mini_element[-1] > node:#node比mini栈里的当前栈顶元素小
                self.mini_element.append(node)
            else:
                self.mini_element.append(self.mini_element[-1])

    def Pop(self):
        if self.stack:
            self.mini_element.pop()
            return self.stack.pop()
        return None

    def min(self):
        return self.mini_element[-1]
    
    def top(self):#网上都写了这个,没觉得有啥用
        if self.stack:
            return self.stack[-1]
        return None

21.输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是都可以为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列 1,2,3,4,5 是某栈的压入顺序,序列 4,5,3,2,1 是该栈序列对应的一个弹出序列,但 4,3,5,1,2 就不可能是该栈序列的弹出序列。(注意:这两个序列的长度是相等的)

解析:借助一个栈,拿着它的入栈序进行入栈,每入一次就看看栈顶元素是不是和它的出栈序一样,一样的话我们也出栈,这里需要循环判断,即出栈完继续看栈顶元素和它的下一个出栈序一样不,一样继续出栈,不一样继续按照它的入栈序入栈,直到入栈序完,此时如果我们的辅助栈如果是空的话,说明它给定的入栈序与出栈序可以匹配(因为每一个入栈元素都会根据出栈序全部出栈),否则说明不匹配。这里有个陷阱,栈的弹出序列不一定是栈的压入序列的倒序,因为有可能在压入的过程中会有弹出。

def IsPopOrder(push1,pop1):#这里有个陷阱,栈的弹出序列不一定是栈的压入序列的倒序,因为有可能在压入的过程中会有弹出
    if not push1 or len(push1) != len(pop1):
        return False
    stack1 = []
    for i in push1:
        stack1.append(i)
        while len(stack1) and stack1[-1] == pop1[0]:#对应位置相等,则同时删除
            stack1.pop()#把stack1[-1] pop出去
            pop1.pop(0)#把pop1[0] pop出去
    if not len(stack1):#遍历后,辅助栈空,则成立
        return True
    return False

push1 = [1,2,3,4,5]
pop1 = [4,5,3,2,1]
pop2 = [4,3,5,1,2]
print(IsPopOrder(push1,pop1))
print(IsPopOrder(push1,pop2))

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

解析:二叉树的层次遍历可以采用一个辅助队列,将二叉树的根节点入队列,然后取出根节点,判断根节点有无左右子树,如果有左右子树入队列,依次这样进行,直到队列为空

class TreeNode(object):
    def __init__(self,data):
        self.data = data
        self.lchild = None
        self.rchild = None

def F(root):
    rootNode = TreeNode(root)
    value = []
    queue = [rootNode]
    if not rootNode:
        return []
    while len(queue):#二叉树从根节点开始,逐一往下找左右节点,并把找到的放入一个辅助队列        
        t = queue.pop(0)
        value.append(t.data)
        if t.lchild:
            queue.append(t.lchild)
        if t.rchild:
            queue.append(t.rchild)
    return value

23.输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出 Yes,否则输出 No。假设输入的数组的任意两个数字都互不相同。(自己注释:二叉查找树它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;它的左、右子树也分别为二叉排序树)

解析:按递归来看,BST(二叉搜索树)的后序序列的合法序列是,对于一个序列S,最后一个元素是x (也就是根),如果去掉最后一个元素的序列为T,那么T满足:T可以分成两段,前一段(左子树)小于x,后一段(右子树)大于x,且这两段(子树)都是合法的后序序列。重复上述过程即可

'''
例如数组[1, 3, 2, 5, 7, 6, 4]就是下图中二叉树的后续遍历序列。
                4
        2               6
    1       3       5       7
'''

def IsAfterOrder(arr):
    if not arr:
        return False
    if len(arr) == 1:
        return True
    else:
        root = arr[-1]
        arr_l = []
        arr_r = []
        for i in range(len(arr)):
            if arr[i] < root:#左子树
                arr_l.append(arr[i])
            else:
                arr_r = arr[i:-1]#arr[i:]是第i+1至最后,arr[i:-1]是第i+1至倒数第2个
                break#不要忘!

        for j in arr_r:
            if j < root:#如果arr[i:-2]确实是右子树,则其所有值都该大于root
                return False

        L = True
        R = True
        if len(arr_l) > 0:
            L = IsAfterOrder(arr_l)
        if len(arr_r) > 0:
            R = IsAfterOrder(arr_r)
        return L and R

arr1 = [1, 3, 2, 5, 7, 6, 4]
print(IsAfterOrder(arr1))
arr2 = [1, 3, 2, 8, 5, 7, 4]
print(IsAfterOrder(arr2))
arr3 = [5, 7, 6, 4]
print(IsAfterOrder(arr3))

注:曾遇到的报错(递归选入了死循环)

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

解析:先考虑根节点,将整数减去根节点的数值,再考虑左右子树,又是一个新的递归问题

class TreeNode(object):
    def __init__(self,data):
        self.data = data
        self.lchild = None
        self.rchild = None

def FindPath(root,k):
    rootNode = TreeNode(root)
    if not rootNode:#二叉树空
        return []
    elif rootNode and not rootNode.lchild and not rootNode.rchild and rootNode.data == k:#二叉树只有根节点
        return [[rootNode.data]]
    else:
        path = []
        lchild = FindPath(rootNode.lchild, k - rootNode.data)
        rchild = FindPath(rootNode.rchild, k - rootNode.data)
        for i in lchild+rchild:
            path.append([rootNode.data] + i)
    return path

注: 

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

解析:未解决

解读一

解读二

 解读三

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

解析:二叉搜索树的中序遍历是一个不减的排序结果,因此可以将二叉树搜索树先中序遍历,将遍历后的结果用相应的指针连接起来

class TreeNode(object):
    def __init__(self,item):
        self.data = item
        self.lchild = None
        self.rchild = None

class Solution(object):
    def Convert(self,item):
        node = TreeNode(item)
        res = self.inorderTraversal(node)
        if len(res) == 0:
            return None
        if len(res) == 1:
            return node
        res[0].lchild = None
        res[0].rchild = res[1]
        res[-1].lchild = res[-2]
        res[-1].rchild = None
        """
        由于res[i-1],故取索引从1起;尾的右节点应指向None,
        应有尾res[len(res)-1]=res[i+1],即i=len(res)-2,故取range(1,len(res)-1)
        """
        for i in range(1,len(res)-1):
            res[i].lchild = res[i-1]
            res[i].rchild = res[i+1]
        return res

    def inorderTraversal(self,node):
        if not node:
            return []
        return self.inorderTraversal(node.lchild) + [node] + self.inorderTraversal(node.rchild)

27.输入一个字符串,按字典序打印出该字符串中字符的所有排列,例如输入字符串 abc,则打印出由字符 a,b,c 所能排列出来的所有字符串 abc, acd, bac, bca, cab 和 cba

解析:待补

28.数组中有一个数组出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为 9 的数组{1,2,3,2,2,2,5,4,2}。由于数组 2 在数组中出现了 5 次,超过了数组长度的一半,因此输出 2。如果不存在则输出 0

解析:遍历列表中的每一个元素,并将元素作为 key,元素出现的次数做为 value,最后统计字典中元素的 value

def MoreThanHalfNum(arr):
    n = len(arr)
    dic = {}
    for i in arr:
        if dic.__contains__(i):#Python 3.x不再支持has_key()函数,而被__contains(‘keyname’)所替代
            'i是key,dic[i]是value,即dic[key]=value'
            dic[i] += 1
        else:
            dic[i] = 1
        # print('i:',i,' ' ,'dic[i]:',dic[i],' ','dic:', dic)

    for key,value in dic.items():
        if value > n/2:
            return key
    return 0

arr = [1,2,3,2,2,2,5,4,2]
print(MoreThanHalfNum(arr))

29. 输入 n 个整数,找出其中最小的 K 个数。例如输入 4,5,1,6,2,7,3,8 这 8 个数字,则最小的 4 个数字是 1,2,3,4

解析:sort排序,取前k个

def F(input,k):
    input.sort()
    if len(input) < k:
        return input
    return input[:k]
print(F([4,5,1,6,2,7,3,8],3))
print(F([4,5,1,6,2,7,3,8],10))

30. HZ 偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一堆模式识别中,常常需要就算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,‐3, ‐2, 7, ‐15, 1, 2, 2 },连续子向量的最大和为 8(从第 0 个开始,到第 3 个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是 1)

解析:待补

31. 求出 1‐13 的整数中 1 出现的次数,并算出 100‐1300 的整数中 1 出现的次数?为此他特别数了一下 1‐13 中包含 1 的数字有 1、10、11、12、13 因此共出现 6 次,但是对于后面的问题他就没辙了。ACMer 希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中 1 出现的次数(从 1 到 n 中 1 出现的次数)

解析:待补

32.输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3, 32, 321},则打印出这三个数字能排成的最小数字为 321323

解析:待补

33.把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。例如 6、8 都是丑数,但 14 不是,因为它包含质因子 7。习惯上我们把 1 当做是第一个丑数。求按从小到大的顺序的第 N 个丑数

解析:待补

34.在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置,如果没有则返回‐1(需要区分大小写)

解析:把字符串append到空列表,由list.count(i)得到元素i在list里的个数,由list.index(i)得到元素i在list里的索引。若字符串为空(没元素)或有元素但没有落单的,则return -1

def F(ss):
    list = []
    if not ss:
        return -1

    for i in ss:
        list.append(i)
    for j in list:
        # print(list.count(j)) #元素j出现在list里的次数
        if list.count(j) == 1:
            return list.index(j) ##元素j出现在list位置的索引
    return -1

ss1 = 'abcddffrrffggsssab'
print(F(ss1))
print('---------------')
ss2 = 'aabbccddeeffgg'
print(F(ss2))
print(',,,,,,,,,,,,,,,')
ss3 = ''
print(len(ss3)) #无字符,满足not ss为真
print(F(ss3))
print('..................')
ss4 = ' '
print(len(ss4)) #有一个空格字符
print(F(ss4))

 

35. 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数 P。并将 P 对 1000000007取模的结果输出。即输出 P%1000000007

解析:待补

36.输入两个链表,找出它们的第一个公共节点

解析:将其中一个链表的值保存在 list 中,之后再遍历第二个链表,检查每个节点的值是不是在 list 中即可

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

def FindFirstCommonNode(item1,item2):
    node1 = Node(item1)
    node2 = Node(item2)
    list1 = []
    while node1:
        list1.append(node1.data)
        node1 = node1.next
    while node2:
        if node2.data in list1:
            return node2
        else:
            node2 = node2.next

注:

 

37.统计一个数字在排序数组中出现的次数

解析:待补

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

解析:树的定义是递归的形式,树的深度可以求左子树和右子树深度的最大值 +1,同样左子树和右子树又是一棵新的树,依次类推,直到叶子结点。

class TreeNode(object):
    def __init__(self,data):
        self.data = data
        self.lchild = None
        self.rchild = None

def TreeDepth(item):
    node = TreeNode(item)
    if not node:#空
        return 0
    elif not node.lchild and not node.rchild:
        return 1
    else:
        return max(TreeDepth(node.lchild)+1, TreeDepth(node.rchild)+1)#每轮迭代加1,直至完毕

39.输入一棵二叉树,判断该二叉树是否是平衡二叉树

解析:使用获取二叉树深度的方法来获取左右子树的深度 ——> 左右深度相减,若大于1返回False ——> 通过递归对每个节点进行判断,若全部均未返回False,则返回True

class TreeNode(object):
    def __init__(self,data):
        self.data = data
        self.lchild = None
        self.rchild = None

class Solution(object):
    def TreeDepth(self,item):#此为整颗树的深度,若输入左/右子树,则得到左/右子树的深度
        node = TreeNode(item)
        if not node:
            return 0
        elif not node.lchild and not node.rchild:
            return 1
        else:
            return max(self.TreeDepth(node.lchild)+1, self.TreeDepth(node.rchild)+1)

    def IsBalanced_Solution(self,item1):
        node1 = TreeNode(item1)
        if not node1:
            return True
        else:
            if abs(self.TreeDepth(node1.lchild) -  self.TreeDepth(node1.rchild)) > 1:
                return False
            return self.IsBalanced_Solution(node1.lchild) and self.IsBalanced_Solution(node1.rchild)#递归

40.一个整型数组里的除了两个数字之外,其他的数字都出现了偶数次。请写程序找出这两个只出现一次的数字

解析:把字符串append到空列表,由list.count(i)得到元素i在list里的个数

def F(ss):
    list = []
    list1 = []
    for i in ss:
        list.append(i)
    for j in ss:
        if list.count(j)==1:
            list1.append(j)
    return list1

ss1 = [1,2,2,3,3,4,4,4,4,5,6]
print(F(ss1))

 

注:

41. 小明很喜欢数学,有一天他在做数学作业时,要求就算出 9‐16 的和,他马上就写出了正确的答案是 100.但是他并不满足于此,他在想究竟有多少中连续的正数序列的和为 100(至少包括两个数)。没过多久,他就得到另一组连续正数和为 100 的序列:18, 19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列?

解析:待补

42.输入一个递增排序的数组和一个数字 S,在数组中查找两个数,使得他们的和正好是 S,如果有多对数字的和等于 S, 输出两个数的乘积最小的。
输出描述:对应每个测试案例,输出两个数,小的先输出。

解析:当有多对儿符合时,由于数组递增的且每对儿之和是定值,则在list里相聚最远的一对儿的乘积便是min的,即最先出现的那对儿。

def F(arr,s):
    list = []
    for k in arr:
        list.append(k)
    for i in list:
        j = s - i
        if list.count(j)>=1 and list.index(i)<list.index(j): #i对应后排的j存在,且符合j在i之后
            print(i, j)
            break #当有多对儿符合时,由于数组递增的且每对儿之和是定值,则在list里相聚最远的一对儿的乘积便是min的,即最先出现的那对儿

import numpy as np
arr = np.array([1,3,4,6,10,12,13,15])
s = 16
F(arr,s)

43.汇编语言汇总有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列 S,请你把循环左移 K 位后的序列输出。例如,字符串序列 S=”abcXYZdef”,要求输出循环左移 3 位后的结果,
即”XYZdefabc”。

解析:很简单

def F(ss,k):
    return ss[k:]+ss[:k]
ss = 'abcXYZdef'
k = 6
print(F(ss,k))

44. 牛客最近来了一个新员工 Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事 Cat 对 Fish 写的内容颇感兴趣,有一天他向 Fish 借来翻看,但却读不懂它的意思。例如,”student a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确句子应该是”I am a student”。Cat 对一一的翻转这些单词顺序可不在行,你能帮助他吗?

解析:句子经split(' ')后,经reverse(), 再用join()拼接成句子

def F(ss):
    print(ss)
    ss1 = ss.split(' ')
    print(ss1)
    ss1.reverse()
    print(ss1)
    print(' '.join(ss1))

ss = 'student a am I'
F(ss)

45. LL 今天心情特别好,因为他去买了一副扑克牌,发现里面居然有 2 个大王,2 个小王(一副牌原本是 54 张)...他随机从中抽出了 5 张牌,想测试自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!红心 A,黑桃 3,小王,大王,方片 5,Oh My God 不是顺子...... LL 不高兴了,他想了想,决定大、小王可以看成任何数字,并且 A 看做 1,J 为 11, Q 为 12, K 为 13。上面的 5 张牌就可以变成 1, 2, 3, 4, 5(大小王分别看做 2 和 4),So Lucky!。LL 决定去买体育彩票啦。现在,要求你使用这副牌模拟以上的过程,然后告诉我们 LL 的运气如何,如果牌能够组成顺子就输出 true,否则就输出 false。为了方便起见,你可以认为大小王是 0

解析:待补

46.每年六一儿童节,牛客都会准备一些小礼物看望孤儿院的小朋友,今年亦是如此。HF 作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友围城一个大圈。然后,他随机指定一个数 m,让编号为 0 的小朋友开始报数。每次喊道 m‐1 的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续 0...m‐1 报数...这样下去...直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的”名侦探柯南”典藏版(名额有限哦!!)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从 0 到 n‐1)

解析:约瑟夫环问题, i = (m ‐ 1 + i)% len(res) 没理解。

47.求 1+2+3+...+n,要求不能使用乘除法、for 、while、if、else、switch、case 等关键字及条件判断语句(A?B:C)

解析:sum()求和

def F(n):
    list = [i+1 for i in range(n)]
    print(sum(list))
F(4)

48. 写一个函数,求两个整数之和,要求在函数体内不得使用+、‐、*、/四则运算符号

解析:append到list里,sum()求和

def F(a, b):
    list = []
    list.append(a)
    list.append(b)
    return sum(list)
print(F(2,9))

注:

           

49. 将一个字符串转换成一个整数(实现 Integer.valueOf(string)的功能,但是 string不符合数字要求时返回 0),要求不能使用字符串转换整数的库函数。数值为 0 或者字符串不是一个合法的数值则返回 0

解析:int(ss),ss不符合的情况当做try异常抛出,返回0

def F(ss):
    try:
        return int(ss)
    except Exception as e:
        return 0

ss1 = '123895'
ss2 = '123abc'
print(F(ss1))
print(F(ss2))

50.在一个长度为 n 的数组里的所有数字都出现在 0 到 n‐1 的范围内。数组中某些数字是重复的,但不知道有几个数字是重复的,也不知道每个数字重复几次。请找出数组中任意一个重复的数字。例如,如果输入长度为 7 的数组{2, 3, 1, 0, 2, 5, 3},那么对应的输出是第一个重复的数字 2

解析:无

def F(arr):
    list = []
    list1 = []
    for i in arr:
        list.append(i)
    for j in list:
        if list.count(j)>1 and list1.count(j)==0:#j在list里不唯一,且还未放到list1
            list1.append(j)
    return list1

import numpy as np
arr1 = np.array([1,4,6,5,6,2,4,1,1])
print(F(arr1))

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

解析:待补

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

解析:待补

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

解析:能够表示为数值的字符串ss,都可以通过float(ss)得到对应数值

def F(ss):
    try:
        return float(ss)
    except:
        return False

ss1 = '5e2'
ss2 = '3.1416'
ss3 = '1.2.3'
ss4 = '1aa2'
print(F(ss1))
print(F(ss2))
print(F(ss3))
print(F(ss4))

 

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

解析:append到list里,用count()寻找

def F(ss):
    list1 = []
    for i in ss:
        list1.append(i)
    for j in list1:
        if list1.count(j) == 1:
            return j

ss1 = 'aabbcccdeefghj'
print(F(ss1))

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

解析:将链表的结点一个一个的加入列表中,如果存在环,则会出现两次,只需要返回出现两次的结点即可

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

def EntryNodeOfLoop(item):
    node = Node(item)
    list1 = []
    if not node:
        return None
    while node:
        list1.append(node)
        if list1.count(node) == 2:#count列表元素技术
            return node
        node = node.next
    return None

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

解析:链表待补

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

解析:二叉树待补

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

解析:用递归判断左右子树是不是对称即可

class TreeNode(object):
    def __init__(self,data):
        self.data = data
        self.lchild = None
        self.rchild = None

class Solution(object):
    def IsSymmetrical(self,item):
        node = TreeNode(item)
        if node == None:#空
            return True
        elif node.lchild == None and node.rchild == None:#只有根节点
            return True
        else:#不只根节点
            return self.judge(node.lchild, node.rchild)

    def judge(self,lchild,rchild):
        if lchild == None or rchild == None:
            return False
        elif lchild.data != rchild.data:#对称节点不等,则不是
            return False
        else:# 对称结点相等,则考虑它们的下一层结点,注意(右结点的右孩子——左结点的左孩子,右结点的左孩子——左结点的右孩子)
            return self.judge(rchild.rchild, lchild.lchild) and self.judge(rchild.lchild, lchild.rchild) 

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

解析:二叉树待补

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

解析:二叉树待补

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

解析:二叉树待补

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

解析:二叉树待补

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

解析:定义一个类,内含自定义方法Insert()与GetMedian()

class M:
    def __init__(self):
        self.data = []
    def Insert(self,i):
        self.data.append(i)
        self.data.sort()
        return self.data
    def GetMedian(self,data):
        n = len(self.data)
        if n%2==1:
            return self.data[n//2]
        else:
            return (self.data[n//2 - 1] + self.data[n//2] ) / 2

f = M()
for i in [7,5,2,4,8,1,3,6]:
    data = f.Insert(i)
print(data)
print(f.GetMedian(data))

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]}

解析:数组长L,窗口大小S,则得到窗口数量 L+S-1

def F(arr, s):
    m = len(arr)
    n = m - s +1
    list = []
    for i in range(n):
        j = max(arr[i:i+s]) #依次滑窗
        list.append(j)
    return list

import numpy as np
arr1 = np.array([2,3,4,2,6,2,5,1])
s = 3
print(F(arr1,s))

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

解析:待补

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

解析:待补

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值