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 1Process 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 二叉树的下一个节点
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。