剑指offer在线编程(08-07)【3】

Date : 2019-08-07

1.  反转链表 (考查知识点:链表)

题目描述

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

分析思路:本题实际上只需要打印出最后一个元素即可。但是同时需要进行链表的反转,则可以在反转的时候直接打印最后遍历的一个元素。反转主要的思想是:首先设置初始Last = None, 然后当pHead非空时,进行如下操作:i) 保存pHead.next到tmp,tmp=pHead.next;  ii) 将pHead.next = last(链表的顺序反转); iii)  然后往后走更新last= pHead 且pHead = tmp.

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        # write code here
        if not pHead or not pHead.next:
            return pHead
        last = None
        while pHead:
            tmp = pHead.next
            pHead.next = last
            last = pHead
            pHead = tmp
        return last

2.  合并两个排序的链表 (考察知识点:链表)

题目描述

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

我的想法是首先根据现有的两个链表建立合并后的链表的表头(需要判断四种情况:p1 p2均为空,p1 p2均非空,p1非空,p2非空四种情况进行链表头的建立),然后后续同样进行后续四种情况进行比较,得到head.next.但是这样的情况没有通过;

通过的代码所给出的:没有通过四种情况进行比较建立链表表头,而是直接初始化一个,然后四种情况进行判断得到后续的元素。

# version of myself  python2.7  没有通过  难道是表头的建立方式有问题。
# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回合并后列表
    def Merge(self, pHead1, pHead2):
        # write code here
        if not pHead1 and not pHead2: # p1 p2均空
            return None
        elif pHead1 and pHead2:      # p1 p2 均非空
            if pHead1.val <= pHead2.val:
                head = pHead1
                pHead1 = pHead1.next
            else:
                head = pHead2
                pHead2 = pHead2.next
        elif pHead1:       # p1 非空
            head = pHead1
            pHead1 = pHead1.next
        elif pHead2:        # p2 非空
            head = pHead2
            pHead2 = pHead2.next
        cur = head
        while pHead1 and pHead2:
            if pHead1.val <= pHead2.val:
                head.next = pHead1
                head = head.next
                pHead1 = pHead1.next
            else:
                head.next = pHead2
                head = head.next
                pHead2 = pHead2.next
        if pHead1:
            head.next = pHead1
        elif pHead2:
            head.next = pHead2
        else:
            return cur.next
 # 已修正:已经通过,是因为最后的return写错了
# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回合并后列表
    def Merge(self, pHead1, pHead2):
        # write code here
        if not pHead1 and not pHead2: # p1 p2均空
            return None
        elif pHead1 and pHead2:      # p1 p2 均非空
            if pHead1.val <= pHead2.val:
                head = pHead1
                pHead1 = pHead1.next
            else:
                head = pHead2
                pHead2 = pHead2.next
        elif pHead1:       # p1 非空
            head = pHead1
            pHead1 = pHead1.next
        elif pHead2:        # p2 非空
            head = pHead2
            pHead2 = pHead2.next
        cur = head
        while pHead1 and pHead2:
            if pHead1.val <= pHead2.val:
                head.next = pHead1
                pHead1 = pHead1.next
            else:
                head.next = pHead2
                pHead2 = pHead2.next
            head = head.next    # 在这一部分的整体结尾处,进行head的更新
        if pHead1:
            head.next = pHead1
        elif pHead2:
            head.next = pHead2
        return cur
 # 牛客上其他人的版本:
# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回合并后列表
    def Merge(self, pHead1, pHead2):
        # write code here
        cur = head = ListNode(0)
        while pHead1 and pHead2:
            if pHead1.val <= pHead2.val:
                head.next = pHead1
                pHead1 = pHead1.next
            else:
                head.next = pHead2
                pHead2 = pHead2.next
            head = head.next  
        head.next = pHead1 or pHead2
        return cur.next   

3.  树的子结构(考察知识: 树)(二叉树B是否为树A的子结构)

题目描述

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

牛客上有人repo的思路:

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def HasSubtree(self, pRoot1, pRoot2):
        # write code here
        result = False
        if pRoot1 != None and pRoot2 != 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
    # 用于递归判断树的每个节点是否相同
    # 需要注意的地方是: 前两个if语句不可以颠倒顺序
    # 如果颠倒顺序, 会先判断pRoot1是否为None, 其实这个时候pRoot2的结点已经遍历完成确定相等了, 但是返回了False, 判断错误
    def DoesTree1haveTree2(self, pRoot1, pRoot2):
        if pRoot2 == None:
            return True
        if pRoot1 == None:
            return False
        if pRoot1.val != pRoot2.val:
            return False
        return self.DoesTree1haveTree2(pRoot1.left, pRoot2.left) and self.DoesTree1haveTree2(pRoot1.right, pRoot2.right)

思路:

1) 首先需要判断树A中是否有与树B的根节点一样的节点。(此处需要递归进行遍历树A)

2)如果树A中存在R节点,则判断A中以R节点为根节点的子树是否与B同结构(此处还需要递归进行遍历树B和以R为根节点的子树,判断其左右孩子节点是否相等,递归的终止条件是我们达到了树R或者树B的叶节点。 )。

# my version:
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def HasSubtree(self, pRoot1, pRoot2):
        # write code here
        result = False
        if pRoot1 != None and pRoot2 != None:
            if pRoot1.val == pRoot2.val:#如果存在相等的节点,则进入判断是否子树结构相等的函数体
                result = self.is_subtree(pRoot1, pRoot2)
            if not result:            # 两棵树非空,且当前节点不相等,则向下遍历,直到相等存在
                result = self.HasSubtree(pRoot1.left, pRoot2) or self.HasSubtree(pRoot1.right, pRoot2)
        return result
    def is_subtree(self, A, B):
        if not B:       # 如果上一B.left或者right为空了,则判断终止。
            return True
        if not A or A.val != B.val:   # 如果B非空,但A非空或者AB相应值不等时,则不存在!
            return False
        return self.is_subtree(A.left,B.left) and self.is_subtree(A.right, B.right) #否则向下进行递归判断,直到进入上方的两个条件进行终止。

4.  二叉树的镜像 (考察知识:树+递归算法)   给出源树,返回相应树的镜像树。

题目描述

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

输入描述:

二叉树的镜像定义:源二叉树 
    	    8
    	   /  \
    	  6   10
    	 / \  / \
    	5  7 9 11
    	镜像二叉树
    	    8
    	   /  \
    	  10   6
    	 / \  / \
    	11 9 7  5

思路:之前没有接触过树的镜像,遇到有点懵,分析一下:例如根节点8,将节点8的左孩子和右孩子进行交换,直接利用自动打包和分配技术即可实现root.lfet, root.right = root.right, root.left.然后向下遍历左孩子和右孩子,同样进行相应左孩子和右孩子的交换。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回镜像树的根节点
    def Mirror(self, root):
        # write code here
        if root == None:
            return None
        else:
            root.left, root.right = root.right, root.left
            self.Mirror(root.left)
            self.Mirror(root.right)
        return root

网上关于树的镜像的完整版代码:

class Solution:
  # 给定一个二叉树,获得其镜像(轴对称)的镜像二叉树:
  # 方式1:生成新的镜像二叉树
  def getMirrorBST(self, root):
    if root == None:
      return
    newTree = treeNode(root.val)
    newTree.right = self.getMirrorBST(root.left)
    newTree.left = self.getMirrorBST(root.right)
    return newTree
  # 方式2:改变给定的二叉树为镜像二叉树
  def turnToMirror(self, root):
    if root == None:
      return
    root.right, root.left = root.left, root.right
    self.turnToMirror(root.left)
    self.turnToMirror(root.right)
    return root
  # 给定二叉树的前序遍历和中序遍历,获得该二叉树
  def getBSTwithPreTin(self, pre, tin):
    if len(pre)==0 | len(tin)==0:
      return None
    root = treeNode(pre[0])
    for order,item in enumerate(tin):
      if root .val == item:
        root.left = self.getBSTwithPreTin(pre[1:order+1], tin[:order])
        root.right = self.getBSTwithPreTin(pre[order+1:], tin[order+1:])
        return root
class treeNode:
  def __init__(self, x):
    self.left = None
    self.right = None
    self.val = x
if __name__ == '__main__':
  flag = "turnToMirror"
  solution = Solution()
  preorder_seq = [1, 2, 4, 7, 3, 5, 6, 8]
  middleorder_seq = [4, 7, 2, 1, 5, 3, 8, 6]
  treeRoot1 = solution.getBSTwithPreTin(preorder_seq, middleorder_seq)
  if flag == "mirrorBST":
    newRoot = solution.getMirrorBST(treeRoot1)
    print(newRoot)
  if flag == "turnToMirror":
    solution.turnToMirror(treeRoot1)
    print(treeRoot1)

5. 顺时针打印矩阵 (考察知识点:数组)

题目描述

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下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度,再打印第一行元素并删除;再逆时针旋转剩下的矩阵90度,打印第一行并删除,……直到剩下的矩阵为空矩阵(数组)

# -*- coding:utf-8 -*-
class Solution:
    # matrix类型为二维列表,需要返回列表
    def printMatrix(self, matrix):
        # write code here
        new_matrix = []
        while matrix:
            new_matrix += matrix.pop(0)#矩阵以二维数组的形式存储,则第一个元素即第一行,同时删除
            if matrix:
                matrix = self.rotate(matrix)  # 对剩下的矩阵进行逆时针旋转90度
        return new_matrix
    def rotate(self, matrix):  # 矩阵旋转可以具体矩阵例子进行分析。
        row = len(matrix) 
        col = len(matrix[0])
        new_matrix = []
        for i in range(col):
            new_line = []
            for j in range(row):
                new_line.append(matrix[j][col-1-i])  
            new_matrix.append(new_line)
        return new_matrix

网上完整例子的代码:

# coding:utf-8
 
class Solution(object):
  def printMatrix(self, matrix):
    # 打印矩阵
    result = []
    while matrix:
      result += matrix.pop(0)
      if matrix:
        matrix = self.rotate(matrix)
    return result
 
  def rotate(self, matrix):
    # 逆时针旋转矩阵
    row = len(matrix)
    col = len(matrix[0])
    # 存放旋转后的矩阵
    new_matrix = []
    # 行列调换
    for i in range(col):
      new_line = []
      for j in range(row):
        new_line.append(matrix[j][col-1-i])
      new_matrix.append(new_line)
    return new_matrix
 
if __name__ == '__main__':
  # 测试代码
  matrix = [
    [1,2,3,4],
    [5,6,7,8],
    [9,10,11,12],
    [13,14,15,16]
  ]
  solution = Solution()
  result = solution.printMatrix(matrix)
  print(result)

6.  包含min函数的栈 (考察知识点:栈)

题目描述

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

分析:要实现查找的O(1)的复杂度,首先想到的是列表(便于查找和索引,但不适合插入和删除任意元素)进行存储和索引。因此自然就利用列表(数组)进行栈的存储,注意的是栈是先进后出的数据结构。l.pop()返回的是最后一个元素,并同时删除l的最后一个元素。

# -*- coding:utf-8 -*-
class Solution:
    l = []
    def push(self, node):  # 给目前的栈增添元素
        # write code here
        self.l.append(node)
    def pop(self):   # 删除刚进入栈的元素,并返回该元素
        # write code here
        return self.l.pop()
    def top(self):  # 用作返回栈的顶端元素,最后进的元素
        # write code here
        return self.l[-1]
    def min(self):  # 对栈中的元素进行求最小值
        # write code here
        return min(self.l)
# 如果上述中所有的带有self.l的地方删除self,则不能通过测试。全局变量的问题,使得l成为了Solution的数据成员。

7. 栈的压入、弹出序列 (考察知识:栈)

题目描述

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

分析思路:判断某一序列是否是一个栈的输出序列也常作为选择题作为考擦,本题的思考角度是:

i)  判断是否有进行函数输出的必要:如果pushV为空或者两个序列的长度不一致,直接给出不能返回popV序列的结果。

ii)  建立模拟栈stack,  首先将两个序列的顶端元素进行判断,是否相等?如果相等,不需要压入模拟栈,直接两个都进行pop(0);

如果不相等,则退而求其次的判断已经压入模拟栈的顶端元素和popV[0]元素是否相等,如果相等,两者分别弹出相应的元素;

如果仍不相等(此时:popv[0]和pushV以及模拟栈stack中的顶端元素都不相等(pushV[0]、stack[-1])),则继续将pushV中的元素压入模拟栈(需要pushV非空)。

如果以上都不能满足,则返回false,不是相应的弹出序列。

否则在最后return True !

 

# -*- coding:utf-8 -*-
class Solution:
    def IsPopOrder(self, pushV, popV):
        # write code here
        if not pushV or  len(pushV)!=len(popV):  # 如果pushV为空或者两个序列的长度不一致,则返回False
            return 0
        stack = []        # 模拟栈,用于暂时存放不满足弹出条件的元素,相当于先压入栈
        while popV:
            if pushV and pushV[0] == popV[0]:  # 如果直接判断两个栈顶的元素相等,则满足弹出条件,直接弹出两个栈的栈顶元素
                pushV.pop(0)
                popV.pop(0)
            elif stack and stack[-1] == popV[0]:  # 如果栈顶元素不满足,则判断已经压入模拟栈的元素顶的元素是否相等,相等则弹出
                stack.pop()
                popV.pop(0)
            elif pushV:  #否则将pushV中的元素压入模拟栈内
                stack.append(pushV.pop(0))
            else:  # 如果将所有pushV的元素压入模拟栈stack,仍没有找到相应的元素,则false
                 return False
        return True

8.  从上往下打印二叉树 (考察知识点:树和队列)

题目描述

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

分析思路:根据题意可以得出必须要额外的建立list,来进行处理。在实际情况中,不仅仅只需要建立一个list,需要建立两个list,一个list l用作存放打印顺序的结果,另一个list表示一个队列(先进先出):用于不断的压入放入l中的左右孩子节点。q.pop(0)和后续的q.append(t.left)和q.append(t.right)保证了:在不断进行压入节点到队列q中时,压入下一层时,是先压入该层的左孩子的左右孩子,然后再压入该层的右孩子的左右孩子。

 

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回从上到下每个节点值列表,例:[1,2,3]
    def PrintFromTopToBottom(self, root):
        # write code here
        if not root:  # 首先判断是否有必要进行下面的函数体,如果树为空没有必要。
            return []
        l = []  # 用于存放打印顺序的结果list
        q = [root]  # 用于存放不断从上往下,从左往右压入左右孩子的队列(先进先出,所以是pop(0))
        while len(q):
            t = q.pop(0)  # 先进先出的队列q
            l.append(t.val)
            if t.left:  # 先压入左孩子,这样可以保证同一层在打印时,是先打印左边的。
                q.append(t.left)
            if t.right:   # 再压入右孩子,保证了:下一层进行压入时,先压入了左孩子的左右孩子,然后再压入右孩子的左右孩子。
                q.append(t.right)
        return l

9.  二叉搜索树的后序遍历序列 (考察知识点:栈和树)

题目描述

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

分析思路:

BST的后序序列的合法序列是,对于一个序列S,最后一个元素是x (也就是根),如果去掉最后一个元素的序列为T,那么T满足:T可以分成两段,前一段(左子树)小于x,后一段(右子树)大于x,且这两段(子树)都是合法的后序序列。完美的递归定义 : ) 。

即如下操作:首先根节点(最后一个元素)是大于所有左子树的元素,小于右子树的元素;后序:(左右中)。找到第一个大于根节点的元素,其是左右子树的分割;再判断右子树是否合法(全部大于root的值);然后再判断左右子树是否合法(递归调用)。注意:左右子树递归判断时的条件。

class Solution:
    def VerifySquenceOfBST(self, sequence):
        # write code here
        if sequence==None or len(sequence)==0:
            return False
        length=len(sequence)
        root=sequence[length-1]
        # 在二叉搜索 树中 左子树节点小于根节点,如果出现了一个节点的值大于root,则应该是右子树的节点
        for i in range(length):
            if sequence[i]>root:
                break
        # 二叉搜索树中右子树的节点都大于根节点,右子树的节点都应该大于root,如果出现了小于root的节点,则该右子树不合法
        for j  in range(i,length):
            if sequence[j]<root:
                return False
        # 判断左子树是否为二叉树,判断左子树是否合法
        left=True
        if  i>0:
            left=self.VerifySquenceOfBST(sequence[0:i])
        # 判断 右子树是否为二叉树,判断右子树是否合法
        right=True
        if i<length-1:
            right=self.VerifySquenceOfBST(sequence[i:-1])
        return left and right

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值