关于树和回溯题目汇总

序言

关于树和回溯题目汇总,好好干饭,好好努力,好好加油哦!

题目一:二叉树返回所有节点值

给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)

二叉树:[3,9,20,null,null,15,7]
    3
   / \
  9  20
    /  \
   15   7
输出:
[
  [3],
  [9,20],
  [15,7]
]

思路:
将每一层的数字都录进去,这里需要两个列表来做,
一个stack是录入每一层的数字,然后变空集再录入另一层。
那么怎么进入下一层?? 比如 stack现在只有一个头node,那么 下一层便是 node的左边和右边。 收入
另一个ans 是录入stack的每一层东西,最后返回ans

 class TreeNode:
     def __init__(self, val=0, left=None, right=None):
         self.val = val
         self.left = left
         self.right = right
def levelOrder(root: TreeNode):
	#如果root是空,则返回[]
	if not root: return []
	stack = []
	stack.append(root)
	ans = []
	while stack:
		#收集stack里面的每一层元素
		ans.append(node.val for node in stack)
		#把上一层的数字放入tmp里,然后就清空stack,准备循环再次收录下一层
		tmp = stack 
		stack = []
		for node in tmp:
			if node.left: stack.append(node.left)
			if node.right: stack.append(node.right)
	return ans 

题目二:二叉树的右视图

给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
二叉树的右视图

输入: [1,2,3,null,5,null,4]
输出: [1, 3, 4]
解释:

   1            <---
 /   \
2     3         <---
 \     \
  5     4       <---

思路是:
把每一层的最后一个node.val 收录入ans ,做法跟上面差不多,只是在收录的时候只要最后一个

def rightSideView(root):
	if not root: return []
	stack = []
	stack.append(root)
	ans = []
	while stack:
		list_ = [node.val for node in stack]
		ans.append(list_[-1])
		tmp = stack 
		stack = []
		for node in tmp:
			if node.left: stack.append(node.left)
			if node.right: stack.append(node.right)
	return ans 

题目三:从后往前录入树的值

lt107: 给定一个二叉树,返回其节点值自底向上的层序遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历

给定二叉树 [3,9,20,null,null,15,7]
    3
   / \
  9  20
    /  \
   15   7
输出:
[
  [15,7],
  [9,20],
  [3]
]

思路:跟上面做的题也差不多,只要最后用[::-1] 倒过来即可。

def reverse(root):
	if not root: return []
	stack = []
	stack.append(root)
	ans = []
	while stack:
		ans.append([node.val for node in stack])
		tmp = stack
		stack = []
		for node in tmp:
			if node.left: stack.append(node.left)
			if node.right: stack.append(node.right)
	return ans[::-1]

题目四:寻找树中的最大值

lt515: 需要在二叉树的每一行中找到最大的值

输入: 

          1
         / \
        3   2
       / \   \  
      5   3   9 

输出: [1, 3, 9]

思路:这也很简单,跟右视图差不多,返回每一层的最大值即可

def largestValues(root):
	if not root: return []
	stack = []
	stack.append(root)
	ans = []
	while stack:
		list_ = [node.val for node in stack]
		ans.append(max(list_))
		tmp = stack
		stack = []
		for node in tmp:
			if node.left: stack.append(node.left)
			if node.right: stack.append(node.right)
	return ans 

题目五:N叉树的前序遍历

N叉树的前序遍历
给定一个 N 叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)。
树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)

输入:root = [1,null,3,2,4,null,5,6]
输出:[[1],[3,2,4],[5,6]]

这里区别是N叉树 看看N叉树的定义是

class Node:
    def __init__(self, val=None, children=None):
        self.val = val
        self.children = children
def levelOrder(root)if not root: return []
	stack = []
	stack.append(root)
	ans = []
	while stack:
		ans.append([node.val for node in stack])
		tmp = stack
		stack = []
		for node in tmp:
			if node.children: 
				for child in node.children:
					stack.append(child)
	return ans

题目六:检查是否相同的树

lt100:给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

输入:       1         1
          / \       / \
         2   3     2   3
        [1,2,3],   [1,2,3]
输出: true

示例 2:
输入:      1          1
          /           \
         2             2
        [1,2],     [1,null,2]
输出: false

示例 3:
输入:       1         1
          / \       / \
         2   1     1   2
        [1,2,1],   [1,1,2]

思路是
对两棵树的每一层的做左右值进行比较 如果有不一样的马上返回False
只有最后q和q都同时变成None的时候,才会返回True 这时候是相同的树
如果有一个先变成None,那也是返回False

def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
	if p is None and q is None: return True 
	if p is None or q is None: return False 
	if p.val != q.val: return False 
	
	return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)

题目七:检查树木是否对称

题目lt101:给定一个二叉树,检查它是否是镜像对称的

输入:
    1
   / \
  2   2
 / \ / \
3  4 4  3
输出:
True

输入:
    1
   / \
  2   2
   \   \
   3    3
输出:
True

思路是
之前我们比较过来两棵树是否相同,只要定义跟上面差不多即可。
把头节点移动之后,比较分开的两棵树 是否对称

def isSymmetric(self,root):
	if not root: return True 
	def checkSame(p1,p2):
		if p1 is None and p2 is None: return True 
		if p1 is None or p2 is None: return False
		if p1.val != p2.val: return False 
		return checkSame(p1.left, p2.right) and checkSame(p1.right,p2.left)
	return checkSame(root.left,root.right)

回忆如何检查两棵树是否相同的code,大同小异。

题目八:树的深度

题目:给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点

    3
   / \
  9  20
    /  \
   15   7
输出:
3
最长深度是3

思路是
每一层都会循环一次 看循环多少次 就是我们需要求的深度
并且要max(左边树能到的最深长度,右边树能到的最深长度) + 1 因为还有root那一层

def maxDepth(self, root: TreeNode) -> int:
	if not root: return 0 
	return max(self.maxDepth(root.left)+1, self.maxDepth(root.right) + 1 )

题目九:括号生成

lt22. 括号生成:数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合

输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]

输入:n = 1
输出:["()"]

思路:这个只能用树来解决了 ,先画出可能的树 然后我们需要剪裁的是哪些树木。
首先我们要意识到 什么样的组合是错误的
(1)右边的 ) 数量 大于 左边 ( 的数量 比如 ()) —> return false
(2)左边的 ( 数量超过 n —> rerturn false
那么怎么构建树呢? 先不考虑剪枝的问题,如何构建你想要的树
开始是 ‘’ 空集,然后下一层是添加 ( 和 )字符。最后的形状应该像这样子

必须设置一个东西来break 树的建立,否则就会一直建立下去


                              ‘’                   
                      /                \
                     (                  )                 
                 /       \           /      \
                ((        ()         )(       ))
               /  \      /   \      /  \       /  \
             (((   (()  ()(  ())   )((  )()   ))(  )))
            / \    /  \  /  \  /  \   /  \  /  \  /  \  /  \
        (((( ((() (()( (()) ...............................
class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        if not n: return []
        ans = []
        def buildTree(node,left,right):
            #node 是收集所有的字符 
            #left是int类型 表示node已经收录了多少个( 
            #right是int类型,表示node已经收录了多少个) 
 
            if right > left: return False
            if left > n: return False
            if len(node) == 2*n: return ans.append(node)

            buildTree(node+'(', left+1, right)
            buildTree(node + ')', left, right+1)
        buildTree('', 0,0)
        return ans 	

题目十:105 前序+中序

105. 从前序与中序遍历序列构造二叉树
根据一棵树的前序遍历与中序遍历构造二叉树。

前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
输出:
    3
   / \
  9  20
    /  \
   15   7

前序遍历:根结点 —> 左子树 —> 右子树
中序遍历:左子树—> 根结点 —> 右子树
思路是:
首先,找到preorder的根节点,根据这个 回到inorder 划分 左子树和右子树
比如我们根据preorder = [3,9,20,15,7] 知道根节点是3 于是 在inorder = [9,3,15,20,7] 可以划分 9是左子树 15 20 7 是右子树
左子树中找出 找出preorder和inorder再次循环 ;
右子树中找出 找出preorder和inorder再次循环。
最后返回root

def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
	if not preorder: return None
	#错误的写法root = preorder[0]
	root = TreeNode(preorder[0])
	index = inorder.index(root.val)

	root.left = self.buildTree(preorder[1:index+1],inorder[0:index])
	root.right = self.buildTree(preorder[index+1:],inorder[index+1:])	
	return root

题目十一:反转二叉树

请翻转 最少 的树中节点,使二叉树的 先序遍历 与预期的遍历行程 voyage 相匹配 。
如果可以,则返回 翻转的 所有节点的值的列表。你可以按任何顺序返回答案。如果不能,则返回列表 [-1]

输入:root = [1,2], voyage = [2,1]
输出:[-1]
解释:翻转节点无法令先序遍历匹配预期行程

输入:root = [1,2,3], voyage = [1,3,2]
输出:[1]
解释:交换节点 23 来翻转节点 1 ,先序遍历可以匹配预期行程。

输入:root = [1,2,3], voyage = [1,2,3]
输出:[]
解释:先序遍历已经匹配预期行程,所以不需要翻转节点。

思路:
相当于比较root和voyage这两棵树 一旦有不一样的时候,就翻转看看能不能,这个太难想了

def flipMatchVoyage(self, root: TreeNode, voyage: List[int]) -> List[int]:
	ans = []
	i = 0 
	def dfs(root):
		nonlocal i 
		if not root: return True 
		if root.val != voyage[i]:return False
		i+=1 
		if root.left and root.left.val != voyage[i]:
			ans.append(root.val)
			root.left, root.right = root.right, root.left 
		return dfs(root.left) and dfs(root.right)
	return ans if dfs(root) else -1 

题目十二:全排列

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
输入:nums = [0,1]
输出:[[0,1],[1,0]]

思路跟括号那差不多,寻找递进规律
[1,2,3]–> [1] + [2,3] 然后 [2,3] --[[2] , [3] 然后 知道 空集 停止

def permute(nums):
	if not nums: return []
	ans = []
	def dfs(nums,lis):
		if not nums: return ans.append(lis)
		for i in range(len(nums)):
			dfs(nums[:i]+nums[i+1:], lis + [nums[i]])
	dfs(nums,[])
	return ans 		
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jianafeng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值