剑指offer(牛客网)day5

1、旋转数组中的最小值

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

# -*- coding:utf-8 -*-
class Solution:
    def minNumberInRotateArray(self, rotateArray):
        if not rotateArray:
            return 0
        for i in range(len(rotateArray)-1):
            if rotateArray[i]>rotateArray[i+1]:
                break
            else:
                continue
        n=len(rotateArray)
        sy=n-i-1
        while sy:
            rotateArray.insert(0,rotateArray.pop())
            sy-=1
        print(rotateArray)
        return rotateArray[0]

zxs = Solution()
print(zxs.minNumberInRotateArray([3, 4, 5, 1, 2]))

在这里插入图片描述

2、二维数组中查找

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
在这里插入图片描述

# -*- coding:utf-8 -*-
class Solution:
    # array 二维列表
    def Find(self, target, array):
        # write code here
        # 1、判断是否存在某个元素,如果存在,则返回True,不存在,则返回False
        # 不存在数组则直接返回
        if not array:
            return False
        # 二维数组的行
        row = len(array)
        # 二维数组的列
        col = len(array[0])
        # 二层循环遍历二维数组
        for i in range(row):
            for j in range(col):
                # 如果目标值等于数组中的值,则找到
                if target == array[i][j]:
                    return True
        # 数组遍历结束后仍未找到
        return False

3、树

3.1 二叉树

满二叉树

一棵二叉树的结点要么是叶子结点,要么它有两个子结点(如果一个二叉树的层数为K,且结点总数是(2^k)-1,则它就是满二叉树。)
在这里插入图片描述

完全二叉树

若设二叉树的深度为k,除第k层外,其它各层(1~k-1)的结点数都达到最大个数,第k层所有的结点都连续集中在最左边,这就是完全二叉树。在这里插入图片描述

二叉搜索树(空树)

所谓二叉搜索树(Binary Search Tree),又叫二叉排序树,简单而言就是左子树上所有节点的值均小于根节点的值,而右子树上所有结点的值均大于根节点的值,左小右大,并不是乱序,因此得名二叉排序树。
在这里插入图片描述

平衡二叉树(空树是特殊的平衡二叉树)

平衡二叉树,又称AVL树,指的是左子树上的所有节点的值都比根节点的值小,而右子树上的所有节点的值都比根节点的值大,且左子树与右子树的高度差最大为1。因此,平衡二叉树满足所有二叉排序(搜索)树的性质。
在这里插入图片描述

3.2 最大堆和最小堆

堆树的定义如下:
(1)堆树是一颗完全二叉树
(2)堆树中某个节点的值总是不大于或不小于其孩子节点的值
(3)堆树中每个节点的子树都是堆树
当父节点的键值总是大于或等于任何一个子节点的键值时为最大堆。 当父节点的键值总是小于或等于任何一个子节点的键值时为最小堆。如下图所示,左边为最大堆,右边为最小堆。
在这里插入图片描述
最大堆的构建:
在这里插入图片描述

3.4 取出方法(深度优先遍历和广度优先遍历)

深度优先广度优先遍历可参考这两篇博客。
深度优先:从某一节点开始,找出与此点邻接的且尚未遍历的点,进行标记,如果遇到没有相邻的,就返回上一个节点重复查找,直至遍历完;
广度优先:某一节点相邻的节点全部先访问完,然后再找相邻的访问,相当于一层一层的访问。

先序,中序和后序参考

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

# 取出方式
# 1、深度优先:先序遍历(根左右),中序遍历(左根右),后续遍历(左右根)
# 2、广度优先:见后面的从上往下打印

# 递归(深度优先):先序
def preorderRecusive(root):
    if root ==None:
        return None
    print(root.val)
    preorderRecusive(root.left)
    preorderRecusive(root.right)
# 中序
def midorderRecusive(root):
    if root ==None:
        return None
    midorderRecusive(root.left)
    print(root.val)
    midorderRecusive(root.right)
# 后序
def latorderRecusive(root):
    if root ==None:
        return None
    latorderRecusive(root.left)
    latorderRecusive(root.right)
    print(root.val)

# 非递归方法(递归和循环是可以相互转换的)
# 递归一般都是放到栈里面做循环
def preAndminorder(root):
    if root ==None:
        return None
    stack=[]  # 表示一个空栈(其实是列表)
    tmpNode = root
    while tmpNode or stack:
        while tmpNode:
            print(tmpNode.val)  # 先序在这里打印
            stack.append(tmpNode)
            tmpNode = tmpNode.left
        node=stack.pop()
        # print(node.val)  # 中序在这里打印
        tmpNode = node.right

def lateorder(root):
    if root ==None:
        return None
    stack=[]  # 表示一个空栈(其实是列表)
    tmpNode = root
    while tmpNode or stack:
        while tmpNode:
            stack.append(tmpNode)
            tmpNode = tmpNode.left
        node=stack[-1]
        tmpNode = node.right
        if node.right == None:
            node=stack.pop()
            while stack and node == stack[-1].right:
                node = stack.pop()
                print(node.val)

if __name__ == '__main__':
    t1 = TreeNode(1)
    t2 = TreeNode(2)
    t3 = TreeNode(3)
    t4 = TreeNode(4)
    t5 = TreeNode(5)
    t6 = TreeNode(6)
    t7 = TreeNode(7)
    t8 = TreeNode(8)
    t9 = TreeNode(9)
    t10 = TreeNode(10)
    t11 = TreeNode(11)
    t12 = TreeNode(12)

    t1.left = t2
    t1.right = t3
    t2.left = t4
    t2.right = t5
    t3.left = t6
    t3.right = t7
    t4.left = t9
    t6.right = t8
    t9.left = t10
    t9.right = t11
    t10.left = t12

    print('*' * 30+'递归方法'+'*'*30)
    print('*' * 30 + '先序遍历' + '*' * 30)
    preorderRecusive(t1)
    print('*' * 30+'中序遍历'+'*'*30)
    midorderRecusive(t1)
    print('*' * 30+'后续遍历'+'*'*30)
    latorderRecusive(t1)

    print('*' * 30+'非递归先序和中序方法'+'*'*30)
    preAndminorder(t1)
    print('*' * 30 + '非递归后序方法' + '*' * 30)
    lateorder(t1)

C:\Users\hubert\Anaconda3\python.exe
H:/python_learning/剑指offer/37、二叉树定义.py
递归方法
先序遍历 1 2 4 9 10 12 11 5 3 6 8 7
中序遍历 12 10 9 11 4 2 5 1 6 8 3 7
后续遍历 12 10 11 9 4 5 2 8 6 7 3 1
非递归先序和中序方法 1 2 4 9 10 12 11 5 3 6 8 7
非递归后序方法 12 10 11 9 4 5 2 8 6 7 3 1

Process finished with exit code 0

3.5 重建二叉树

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

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回构造的TreeNode根节点
    def reConstructBinaryTree(self, pre, tin):
        # write code here
        if not pre or not tin:
            return None
        if len(pre) != len(tin):
            return None
        # 取出左右子树的值
        root = pre[0]
        rootNode = TreeNode(root)
        pos =tin.index(root)
        tinleft = tin[:pos]
        tinright = tin[pos+1:]
        preleft = pre[1:pos+1]
        preright = pre[pos+1:]
        
        leftNode=self.reConstructBinaryTree(preleft, tinleft)
        rightNode=self.reConstructBinaryTree(preright, tinright)
        rootNode.left = leftNode
        rootNode.right = rightNode
        return rootNode

3.6 最小的K个数

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

# -*- coding:utf-8 -*-
class Solution:
    def GetLeastNumbers_Solution(self, tinput, k):
        # write code here
        if not tinput:
            return []
        if k>len(tinput):
            return []
        tinput.sort()
        li=[]
        for i in range(k):
            li.append(tinput[i])
        return li

方法2:
解题思路:
求最小K值,用最大堆,然后每一个数与根比较,大于根不要,小于根就替换根值,重新排列最大堆,直至n个整数走完即可。

在这里插入图片描述

# -*- coding:utf-8 -*-
class Solution:
    def GetLeastNumbers_Solution(self, tinput, k):
        # write code here
        # 1、创建或插入最大堆
        def creatMaxdui(num):
            maxdui.append(num)
            currentIndex=len(maxdui)-1 # 当前节点index
            while currentIndex != 0:
                parentIndex = (currentIndex-1)//2  # 父节点
                if maxdui[parentIndex] < maxdui[currentIndex]:
                    maxdui[parentIndex],maxdui[currentIndex]=maxdui[currentIndex],maxdui[parentIndex]
                else:
                    break
        # 2、调整最大堆
        def adjustMaxdui(num):
            if num < maxdui[0]:
                maxdui[0]=num
            index = 0
            while index < len(maxdui):
                leftIndex =index*2+1
                rightIndex = index*2+2
                if rightIndex < len(maxdui):
                    if maxdui[rightIndex] < maxdui[leftIndex]:
                        largIndex = leftIndex
                    else:
                        largIndex = rightIndex
                elif leftIndex < len(maxdui):
                    largIndex = leftIndex
                else:
                    break

                if maxdui[index] < maxdui[largIndex]:
                    maxdui[index],maxdui[largIndex] = maxdui[largIndex],maxdui[index]
                index = largIndex

        if not tinput:
            return []
        if k > len(tinput):
            return []
        if k <= 0:
            return []
        maxdui = []
        for i in range(len(tinput)):
            if i < k:
                creatMaxdui(tinput[i])
            else:
                adjustMaxdui(tinput[i])
        maxdui.sort()
        return maxdui

3.7 二叉树的深度

输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
class Solution:
    def TreeDepth(self, pRoot):
        # write code here
        # 使用层次遍历,当树为空直接返回0
        if pRoot is None:
            return 0
        # 使用递归
        # 如果该树只有一个结点,它的深度为1.如果根节点只有左子树没有右子树,
        # 那么树的深度为左子树的深度加1;同样,如果只有右子树没有左子树,
        # 那么树的深度为右子树的深度加1。如果既有左子树也有右子树,
        # 那该树的深度就是左子树和右子树的最大值加1.
        count = max(self.TreeDepth(pRoot.left), self.TreeDepth(pRoot.right)) + 1
        return count
    pass
pass

3.8二叉树的镜像

在这里插入图片描述

class Solution:
    # 返回镜像树的根节点
    def Mirror(self, root):
        # write code here
        if root != None:
            root.left,root.right = root.right,root.left
            self.Mirror(root.left)
            self.Mirror(root.right)

3.9树的子结构

输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
解题思路:
在这里插入图片描述
查找A中是否存在树B结构一样的子树,可以分为两步:
第一步,在树A中找到和树B的根节点的值一样的节点R
第二步,判断A中以R为根节点的子树是不是包含和树B一样的结构
以上面为例,先在A中找到值为8的节点,接着判断树A的根节点下面的子树是不是含有和树B一样的结构。在A中根节点的左子节点为8,而树B的根节点的左子节点为9,对应两个节点不同。
接着找8的节点,在A中第二层找到,然后进行第二步的判断(判断这个节点下面的子树是否含有树B一样的结构)

# -*- 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
        if not pRoot1 or not pRoot2:
            return False
        # or:一个为真就是真;and:全为真才是真
        return self.is_subtree(pRoot1, pRoot2) or self.HasSubtree(pRoot1.left, pRoot2) or self.HasSubtree(pRoot1.right,
                                                                                                          pRoot2)

    def is_subtree(self, A, B):
        if not B:  # 可能对应的是下面B.left的值
            return True
        if not A or A.val != B.val:
            return False
        # A.val == B.val 并且A和B都不是空
        return self.is_subtree(A.left, B.left) and self.is_subtree(A.right, B.right)

3.10 从上往下打印二叉树(广度优先遍历)

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

# -*- 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 []
        li=[]
        support= [root]  #将根节点放进列表中
        while support:
            tmpNode = support[0]
            li.append(tmpNode.val)
            
            if tmpNode.left:
                support.append(tmpNode.left)
            if tmpNode.right:
                support.append(tmpNode.right)
                
            del support[0]  # 执行过就删除
        return li

3.11 二叉搜索树的后序遍历

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
解题思路:
最后一个是根节点;
大于根节点的是右子树
小于根节点的是左子树

# -*- coding:utf-8 -*-
class Solution:
    def VerifySquenceOfBST(self, sequence):
        # write code here
        if not sequence:
            return False  # 本题空树不属于二叉搜索树,理论上是True
        rootVale = sequence[-1]
        del sequence[-1]
        index = None
        for i in range(len(sequence)):
            # and 全真才真
            if index == None and sequence[i] > rootVale:  # 找比根大的数index
                index = i  # index代表第一个大于根节点的数出现的下标位置
            if index != None and sequence[i] < rootVale:  # 继续循环,如果又找到比根小的index,就出错
                return False
        # 递归
        if sequence[:index] == []:  # 没有左子树
            leftdata = True
        else:
            leftdata = self.VerifySquenceOfBST(sequence[:index])
        if sequence[index:] == []:
            rightdata = True
        else:
            rightdata = self.VerifySquenceOfBST(sequence[index:])

        return leftdata and rightdata

3.12二叉树中和为某一数值的路径(广度优先遍历看这个)

输入一颗二叉树的根节点和一个整数,按字典序打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径(路经长的先输出)。
解题思路:
这道题比较简单,但是要注意看好题目,笔者在这里踩过坑,没有注意到根到叶子才算一条路径
我们只要对树进行层次遍历就行了,然后依次将节点存放到数组里,并与整数进行减法运算

在这里插入图片描述
在这里插入图片描述

# -*- coding:utf-8 -*-
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
class Solution:
    def FindPath(self, root, expectNumber):
        if not root:
            return []
        a = []
        result = []
        r = []
        a.insert(0,root)  # 相当于在前面插入
        result.append([root.val])
        while a:
            t = len(a)
            for i in range(t):
                temp = a.pop()  # a输出的就是广度搜索遍历(层次)
                i = result[0]
                if temp.left:
                    result.append(i+[temp.left.val])
                    a.insert(0, temp.left)
                if temp.right:
                    result.append(i+[temp.right.val])
                    a.insert(0, temp.right)
                if not temp.left and not temp.right and sum(result[0]) == expectNumber:
                    r.append(result[0])
                result.pop(0)
        return r[::-1]   # 多的先输出

if __name__ == '__main__':
    t1 = TreeNode(5)
    t2 = TreeNode(2)
    t3 = TreeNode(9)
    t4 = TreeNode(1)
    t5 = TreeNode(16)
    t6 = TreeNode(6)
    t7 = TreeNode(11)
    t8 = TreeNode(3)

    t1.left = t2
    t1.right = t3
    t2.left = t4
    t2.right = t5
    t3.left = t6
    t3.right = t7
    t6.left = t8

    s=Solution()
    print(s.FindPath(t1, 23))

在这里插入图片描述

3.13 二叉搜索树与双向链表

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
在这里插入图片描述
**解题思路:

  • .该题的关键是,如何将左子树的最大值与右子树的最小值通过根root连接起来,比如题目的8和12,这也是细节部分
  • 输出时候:左子树的最左边就是头**
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def Convert(self, pRootOfTree):
        # write code here
        if pRootOfTree == None:
            return None
        def find_right(node):
            while node.right:
                node = node.right
            return node

        leftNode = self.Convert(pRootOfTree.left)
        rightNode = self.Convert(pRootOfTree.right)

        retNode = leftNode
        if leftNode:
            leftNode = find_right(leftNode)
        else:
            retNode = pRootOfTree

        pRootOfTree.left = leftNode
        pRootOfTree.right = rightNode
        if leftNode != None:
            leftNode.right = pRootOfTree
        if rightNode!= None:
            rightNode.left = pRootOfTree
        return retNode

3.14 对称的二叉树

请实现一个函数,用来判断一棵二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
在这里插入图片描述
解题思路:
对称二叉树定义: 对于树中 任意两个对称节点 L和 R ,一定有:

  • L.val = R.valL.val=R.val :即此两对称节点值相等。
  • L.left.val =R.right.val :即 L 的 左子节点 和 R 的 右子节点 对称;
  • L.right.val = R.left.val:即 L 的 右子节点 和 R的左子节点 对称。
    在这里插入图片描述
    终止条件
  • 当 L 和 R 同时越过叶节点: 此树从顶至底的节点都对称,因此返回 true ;
  • 当 L 或 R中只有一个越过叶节点:此树不对称,因此返回 false ;
  • 当节点 L值 不等于节点 R值: 此树不对称,因此返回 false ;
    recur=juge在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
# -*- 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 juge(L,R):
            if not L and not R: 
                return True
            if not L or not R or L.val != R.val:
                return False
            return juge(L.left,R.right) and juge(L.right,R.left)
        # 特例,根节点为空,返回True
        if pRoot == None:
            return True
        else:
            return juge(pRoot.left,pRoot.right)

3.15 二叉树的下一个节点

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值