剑指offer:树有关的题目(python)

树节点上存储val,然后两个指针分别是left和right。
在这里插入图片描述

#定义一个二叉树
class TreeNode(object):
	def __init__(self,x):
		self.val = x
		self.left = None
		self.right = None.
#存储二叉树
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)
	t1.left = t2
	t1.right = t3
	t2.left = t4
	t2.right = t5
	t3.left = t6
	t3.right = t7
	t6.right = t8
#取出二叉树
#1.深度优先:
#先序遍历(根放最先):根左右,1,2,4,5,3,6,8,7
def preOrderRecusive(root):
	if root == None:
		return None
	print(root.val)
	#左节点是一颗树,右节点也是一颗树
	preOrderRecusive(root.left)
	preOrderRecusive(root.right)
preOrderRecusive(t1)
#中序遍历(根放中间):左根右,4,2,5,1,6,8,3,7
def midOrderRecusive(root):
	if root == None:
		return None
	midOrderRecusive(root.left)
	print(root.val)
	midOrderRecusive(root.right)
midOrderRecusive(t1)
#后序遍历(根放最后):左右根,4,5,2,8,6,7,3,1
def latOrderRecusive(root):
	if root == None:
		return None
	latOrderRecusive(root.left)
	latOrderRecusive(root.right)
	print(root.val)
latOrderRecusive(t1)
#用非递归的方式实现,递归就是一个栈(前序遍历)
def preOrder(root):
	if root == None:
		return None
	stack = []
	tmpNode = root
	#tmpNode和stack中有一个不为空则进入循环
	while tmpNode or stack:
		while tmpNode:
			print(tmpNode.val)
			stack.append(tmpNode)
			tmpNode = tmpNode.left
		#只pop出一个元素,第一次为4
		node = stack.pop()
		#如果在这print(node.val)就是中序遍历
		tmpNode = node.right
		
#非递归实现后续遍历
def lastOrder1(root):
    if root == None:
        return None
    stack = []
    tmpNode = root
    while stack or tmpNode:
        while tmpNode:
            stack.append(tmpNode)
            tmpNode = tmpNode.left
        node = stack[-1]
        tmpNode = node.right
        if tmpNode == None:
            node = stack.pop()
            print(node.val)
        while stack and node == stack[-1].right:
            node = stack.pop()
            print(node.val)
#2.广度优先:广度优先搜索是按层来处理顶点,
#距离开始点最近的那些顶点首先被访问,
#而最远的那些顶点则最后被访问

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

前序遍历的第一个为根节点,可以通过这个根节点作为中序遍历的索引,索引左边的为根节点的左子树,右边为根节点的右子树。然后递归形成树。

def reConstructBinaryTree(self,pre,tin):
	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

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

树的子结构:
在这里插入图片描述
先判断两个的根节点是不是一样的,再判断左右节点是不是一样的。如果一样返回,不一样的话继续遍历。

def HasSubtree(self,pRoot1,pRoot2):
	def hasEqual(pRoot1,pRoot2):
		if pRoot2 == None:
			return True
		if pRoot1 == None:
			return False
		if pRoot1.val == pRoot2.val:
			if pRoot2.left == None:
				leftEqual = True
			else:
				leftEqual = hasEqual(pRoot1.left,pRoot2.left)
			if pRoot2.right == None:
				rightEqual = True
			else:
				rightEqual = hasEqual(pRoot1.right,pRoot2.right)
			return leftEqual and rightEqual
		return False
		
	if pRoot2 == None or pRoot1 == None:
		return False
	#判断root节点是否一样
	if pRoot1.val == pRoot2.val:
		ret = hasEqual(pRoot1,pRoot2)
		if ret:
			return True
	#判断left节点是否一样
	ret = self.HasSubtree(pRoot1.left,pRoot2)
	if ret:
		return True
	#判读right节点是否一样
	ret = self.HasSubtree(pRoot1.right,pRoot2)
	if ret:
		return ret

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

树的左右节点对换位置即树的镜像。在处理二叉树的时候一般都用递归。

def Mirror(self,root):
	if root == None:
		return None
	root.left,root.right = root.right,root.left
	self.Mirror(root.left)
	self.Mirror(root.right)

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

def PrintFromTopToBottom(self,root):
	if root == None:
		return []
	support = [root]
	ret = []
	while support:
		tmpNode = support[0]
		ret.append(tmpNode.val)
	
		if tmpNode.left:
			support.append(tmpNode.left)
		if tmpNode.right:
			support.append(tmpNode.right)
		del support[0]
	return ret

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

二叉搜索树:根节点的左子树上的值都比根节点小,右子树上的值都比根节点大。(空树也是二叉搜索树)

def VerifySquenceOfBST(self,sequence):
	if sequence == []:
		return False
	rootNum = sequence[-1]
	del sequence[-1]
	index = None
	for i in range(len(sequence)):
		#找到分界处,左子树都比根节点小,右子树都比根大,找到第一个比根节点大的数
		if index == None and sequence[i] > rootNum:
			index = i
		#如果右子树的值比根节点小则返回False
		if index != None and sequence[i] < rootNum:
			return False
	if sequence[:index] == []:
		return True
	else:
		leftRet = self.VerifySquenceOfBST(sequence[:index])
	if sequence[index:] == []:
		return True
	else:
		rightRet = self.VerifySquenceOfBST(sequence[index:])
	return leftRet and leftRet

题目:
输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。

这个整数是一个值,要在树中找路径,把所进过的节点加起来的和为这个值,则为一条所需要的路径,但一定要直到叶子节点。
用广度优先进行遍历
在这里插入图片描述

import copy
def FindPath(self,root,expectNumber):
	if root == None:
		return []
	#广度优先遍历
	ret = []
	supprot = [root]
	supportArrayList = [[root.val]]
	while support:
		tmpNode = support[0]
		tmpArrayList = supportArrayList[0]
		#判断路径上的值是不是期望值
		if tmpNode.left == None and tmpNode.right == None:
			if sum(tmpArrayList) == expectNumber:
				ret.insert(0,tmpArrayList)
		if tmpNode.left:
			support.append(tmpNode.left)
			#浅拷贝
			newTmpArrayLsit=copy.copy(tmpArrayList)
			newTmpArrayList.append(tmpNode.left.val)
			supportArrayList.append(newTmpArrayList)
		if tmpNode.right:
			support.append(tmpNode.right)
			newTmpArrayLsit=copy.copy(tmpArrayList)
			newTmpArrayList.append(tmpNode.right.val)
			supportArrayList.append(newTmpArrayList)
		del supportArrayList[0]
		del support[0]
	return ret

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

因为是二叉搜索树,所以它的中序遍历刚好是它的双向链表。因为要找到它根节点的左子树中最右的节点与根节点相连,找到根节点的右子树中最左的节点和它相连。

    def Convert(self, pRootOfTree):
        # write code here
        if not pRootOfTree:
            return None
        mid = []
        def MidOrder(root):
            if root == None:
                return None
            MidOrder(root.left)
            mid.append(root)
            MidOrder(root.right)
        MidOrder(pRootOfTree)
        for i in range(len(mid)-1):
            #mid[i] = TreeNode(mid[i])
            #mid[i+1] = TreeNode(mid[i+1])
            mid[i].right = mid[i+1]
            mid[i+1].left = mid[i]
        return mid[0]

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

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

在最大堆中父节点的值都会比子节点的值大。最小堆则根节点是要比子节点小。(它们都是完全二叉树)其中时间复杂度和替换复杂度为O(log(n))。子节点想找到父节点(index-1)//2,父节点想找到左节点index2+1,右节点index2+2。
因为我们用一个列表去储存最大堆,在列表中的排序是有规律的,根左右,所以可以通过上面的找到父节点和左右节点。

所以我们需要创建一个最大堆,这个最大堆包含k个数。然后插入数进行调整。

def GetLeastNumbers_solution(self,tinput,k):
	
	#创建最大堆
	def createMaxHeap(num):
		#先把数插入到数组的最后
		maxHeap.append(num)
		#然后跟它的父节点做比较和替换
		currentIndex = len(maxHeap) - 1
		#当比较到最顶端的父节点就结束
		while currentIndex != 0:
			parentIndex = (currentIndex-1)//2
			if maxHeap[parentIndex] < maxHeap[currentIndex]:
			maxHeap[parentIndex],maxHeap[currentIndex] = maxHeap[currentIndex],maxHeap[parentIndex]
			currentIndex = parentIndex
			else:
				break
	#调整最大堆,头节点发生改变
	def adjustMaxHeap(num):
		if num < maxHeap[0]:
			maxHeap[0] = num
		index = 0
		maxHeapLen = len(maxHeap)
		while index < maxHeapLen:
			leftIndex = index*2+1
			rightIndex = index*2+2
			largerIndex = 0
			if rightIndex < maxHeapLen:
				if maxHeap[rightIndex] < maxHeap[leftIndex]:
					largerIndex = leftIndex
				else:
					largerIndex = rightIndex
			elif leftIndex < maxHeapLen:
				largerIndex = leftIndex
			else:
				break

			#当输入进来的数小于子节点最大的数则替换
			if maxHeap[index] < maxHeap[largerIndex]:
				maxHeap[index],maxHeap[largerIndex] = maxHeap[largerIndex],maxHeap[index]
			index = largerIndex
			else:
				break


		maxHeap = []
		if len(tinput) < k or k <= 0:
			return []
		for i in range(len(tinput)):
			if i < k:
				creatMaxHeap(tinput[i])
			else:
				adjustMaxHeap(tinput[i])
		maxHeap.sort()
		return maxHeap

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

定义出一个最大堆和一个最小堆,把小的数放入最大堆中,把大的数放入最小堆中。如果最终的数的个数是奇数则输出最大堆的对顶,如果是偶数则(最大堆的堆顶+最小堆的对顶)//2

def __init__(self):
	self.littlevalueMaxHeap = []
	self.bigvalueMinHeap = []
	self.maxHeapCount = 0
	self.minHeapCount = 0
def Insert(self,num):
	
def createMaxHeap(self,num):
	self.littlevalueMaxHeap.append(num)
	tmpIndex = len(self.littlevalueMaxHeap) - 1
	while tmpIndex:
		parentIndex = (tmpIndex - 1)//2
		if self.littValueMaxHeap[parentIndex] < self.littleValueMaxHeap[tmpIndex]:
			self.littValueMaxHeap[parentIndex],self.littleValueMaxHeap[tmpIndex]=self.littleValueMaxHeap[tmpIndex],self.littValueMaxHeap[parentIndex]
		else:
			break

def adjuestMaxHeap(self,num)
	if num < self.littleValueMaxHeap[0]:
		self.littleValueMaxHeap[0] = num
		tmpIndex = 0
		while tmpIndex < len(self.littleValueMaxHeap):
			leftIndex = tmpIndex*2+1
			rightIndex = tmpIndex*2+2
			largerIndex = 0
			if rightIndex < len(self.littleValueMaxHeap):
				largerIndex = rightIndex if self.littleValueMaxHeap[left] < self,littleValueMaxHeap[right] else leftIndex
			elif leftIndex < len(self.littleValueMaxHeap):
				largerIndex = leftIndex
			else:
				break
			
			if self.littleValueMaxHeap[index] < self.littleValueMaxHeap[largerIndex]:
				self.littleValueMaxHeap[largerIndex],self.littleValueMaxHeap[index] = self.littleValueMaxHeap[index],self.littleValueMaxHeap[largerIndex]
				index = largerIndex
			else:
				break

def createMinHeap(self,num):
	self.bigvalueMinHeap.append(num)
	tmpIndex = len(self.bigvalueMinHeap) - 1
	while tmpIndex:
		parentIndex = (tmpIndex - 1)//2
		if self.bigvalueMinHeap[tmpIndex] < self.bigvalueMinHeap[parentIndex]:
			self.bigvalueMinHeap[parentIndex],self.bigvalueMinHeap[tmpIndex]=self.bigvalueMinHeap[tmpIndex],self.bigvalueMinHeap[parentIndex]
		else:
			break	

def adjuestMinHeap(self,num)
	if num < self.bigvalueMinHeap[0]:
		self.bigvalueMinHeap[0] = num
		tmpIndex = 0
		while tmpIndex < len(self.self.bigvalueMinHeap):
			leftIndex = tmpIndex*2+1
			rightIndex = tmpIndex*2+2
			smallIndex = 0
			if rightIndex < len(self.bigvalueMinHeap):
				smallIndex = rightIndex if self.bigvalueMinHeap[right] < self.bigvalueMinHeap[left] else leftIndex
			elif leftIndex < len(self.bigvalueMinHeap):
				largerIndex = leftIndex
			else:
				break
			
			if self.bigvalueMinHeap[smallIndex] < self.bigvalueMinHeap[index]:
				self.bigvalueMinHeap[smallIndex],self.bigvalueMinHeap[index] = self.bigvalueMinHeap[index],self.bigvalueMinHeap[smallIndex]
				index = smallIndex
			else:
				break	

def Insert(self,num):
	
			

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

1.寻找右子树,如果存在就一直找到右子树的最左边就是下一个节点
2.没有右子树,就寻找它的父节点,一直找到它是父节点的左子树,打印父节点

def GetNext(self,pNode):
	if pNode.right:
		tmpNode = pNode.right
		while tmpNode.left:
			tmpNode = tmpNode.left
		return tmpNode
	else:
		tmpNode = pNode
		while tmpNode.next:
			if tmpNode.next.left == tmpNode:
				return tmpNode.next
			tmpNode = tmpNode.next
		return None

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

对称二叉树:
在这里插入图片描述
根节点的左子树等于另外那个根节点的右子树,根节点的右子树等于另外那个节点的左子树。

def isSymmetrical(self,pRoot):
	def is Mirror(left,right):
		if left == None and right == None:
			return True
		elif left == None or right == None:
			return False
		if left.val != right.val:
			return False
		ret1 = isMirror(left.left,right.right)
		ret2 = isMirror(left.right,right.left)
		return ret1 and ret2

	if pRoot == None:
		return True
	return isMirror(pRoot.left,pRoot.right)

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

在这里插入图片描述
用两个栈来实现。

def Print(self,pRoot):
	if pRoot == None:
		return []
	stack1 = [pRoot]
	stack2 = []
	ret = []
	
	while stack1 or stack2:
		if stack1:
			tmpRet = []
			while stack1:
				tmpNode = stack1.pop()
				tmpRet.append(tmpNode.val)
				if tmpNode.left:
					stack2.append(tmpNode.left)
				if tmpNode.right:
					stack2.append(tmpNode.right)
			ret.append(tmpRet)

	if stack2:
		tmpRet = []
		while stack2:
			tmpNode = stack2.pop()
			tmpRet.append(tmpNode)
			if tmpNode.right:
				stack1.append(tmpNode.right)
			if tmpNode.left:
				stack1.append(tmpNode.left)
		ret.append(tmpRet)
	return ret
			

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

用两个队列可以实现。

def print(self,pRoot):
	if pRoot == None:
		return []
	queue1 = [pRoot]
	queue2 = []
	ret = []
	
	while queue1 or queue2:
		if queue1:
			tmpRet = []
			while queue1:
				tmpNode = queue1[0]
				tmpRet.append(tmpNode.val)
				del queue1[0]
				if tmpNode.left:
					queue2.append(tmpNode.left)
				if tmpNode.right:
					queue2.append(tmpNode.right)
				ret.append(tmpRet)
			if queue2:
				tmpRet = []
				while queue2:
					tmpNode = queue2[0]
					tmpRet.append(tmpNode.val)
					def queue2[0]
					if tmpNode.left:
					queue1.append(tmpNode.left)
				if tmpNode.right:
					queue1.append(tmpNode.right)
				ret.append(tmpRet)
	return ret

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

二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。

二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。

例如,我们可以把一个只有根节点为1的二叉树序列化为"1,",然后通过自己的函数来解析回这个二叉树

遍历二叉树,若遇到叶子节点则加入‘#’,若只有左子树没有右子树的叶子节点再加一个‘#’

def Serialize(self,root):
	retList = []
	#前序遍历
	def preOrder(root):
		if root == None:
			retList.append('#')
			return
		retList.append(str(root.val))
		preOrder(root.left)
		preOrder(root.right)
	preOrder(root)
	return ' '.join(retList)

def Deserialize(self,s):
	retList = s.split()
	def dePreOrder():
		if preList == []:
			return None
		rootVal = retList[0]
		del retList[0]
		if rootVal == '#'
			return None
		node = TreeNode(int(rootVal))
		#左子树
		leftNode = dePreOrder()
		#右子树
		rightNode = dePreOrder()
		
		node.left = leftNode
		node.right = rightNode
		return node

	pRoot = dePreOrder()
	return pRoot
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值