1. 平衡二叉树

输入一棵二叉树,判断该二叉树是否是平衡二叉树。

解:

要么是一颗空树,要么左右子树都是平衡二叉树且左右子树深度之差不超过1

 1 # class TreeNode:
2 # def __init__(self, x):
3 # self.val = x
4 # self.left = None
5 # self.right = None
6 class Solution:
7 def IsBalanced_Solution(self, pRoot):
8 # write code here
9 if not pRoot:
10 return True
11 res = abs(self.getDepth(pRoot.left) - self.getDepth(pRoot.right))
12 if res <= 1 and self.IsBalanced_Solution(pRoot.left) and self.IsBalanced_Solution(pRoot.right):
13 return True
14 return False
15
16 def getDepth(self, root):
17 if not root:
18 return 0
19 if not (root.left or root.right):
20 return 1
21 return max(self.getDepth(root.left), self.getDepth(root.right)) + 1

  

2. 二叉树的深度

输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

解:

层次遍历,bfs 实现

 1 # class TreeNode:
2 # def __init__(self, x):
3 # self.val = x
4 # self.left = None
5 # self.right = None
6 class Solution:
7 def TreeDepth(self, pRoot):
8 # write code here
9 if not pRoot:
10 return 0
11 depth = 0
12 queue = [pRoot]
13 while queue:
14 tmp = []
15 for i in range(len(queue)):
16 node = queue.pop(0)
17 tmp.append(node.val)
18 if node.left:
19 queue.append(node.left)
20 if node.right:
21 queue.append(node.right)
22 if tmp:
23 depth += 1
24 return depth

  

dfs 实现,只需要记录深度即可,不用记录节点

 1 # class TreeNode:
2 # def __init__(self, x):
3 # self.val = x
4 # self.left = None
5 # self.right = None
6 class Solution:
7 def TreeDepth(self, pRoot):
8 # write code here
9 if not pRoot:
10 return 0
11 self.depth = 0
12 def helper(node, level):
13 if not(node.left or node.right):
14 self.depth = max(self.depth, level)
15 return
16 if node.left:
17 helper(node.left, level+1)
18 if node.right:
19 helper(node.right, level+1)
20
21 helper(pRoot, 1)
22 return self.depth

  

3. 二叉树的下一个节点

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

解:

几种可能的情况考虑一下即可

 1 # class TreeLinkNode:
2 # def __init__(self, x):
3 # self.val = x
4 # self.left = None
5 # self.right = None
6 # self.next = None
7 class Solution:
8 def GetNext(self, pNode):
9 # write code here
10 if not pNode:
11 return
12
13 # 如果当前节点有右子树,中序遍历的下一个节点是其右子树的最左节点
14 if pNode.right:
15 pRight = pNode.right
16 while pRight.left:
17 pRight = pRight.left
18 return pRight
19
20 # 如果当前节点没有右子树,但是当前节点是其父节点的左子节点,下一个节点是其父节点
21 if pNode.next and pNode.next.left == pNode:
22 return pNode.next
23
24 # 如果当前节点没有右子树,但是是其父节点的右子节点,则一直向上遍历,找到是其父节点的左子结点的pNode
25 # 当前节点的下一个节点就是pNode的父节点
26 if pNode.next and pNode.next.right == pNode:
27 while pNode.next and pNode != pNode.next.left:
28 pNode = pNode.next
29 return pNode.next
30 return

  

4. 对称的二叉树

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

解:

递归实现,判断给定两个节点为根的子树是否镜像,首先根节点的值要相等,其次A的左子树和B的右子树、A的右子树和B的左子树要递归的进行判断

 1 # class TreeNode:
2 # def __init__(self, x):
3 # self.val = x
4 # self.left = None
5 # self.right = None
6 class Solution:
7 def isSymmetrical(self, pRoot):
8 # write code here
9 if not pRoot:
10 return True
11 return self.compare(pRoot.left, pRoot.right)
12
13 def compare(self, p1, p2):
14 if p1 == None :
15 return p2 == None
16 if p2 == None:
17 return False
18 if p1.val != p2.val:
19 return False
20 return self.compare(p1.left, p2.right) and self.compare(p1.right, p2.left)

  

dfs,用栈实现,成对取出成对插入,镜像:左左配右右,左右配右左

 1 # class TreeNode:
2 # def __init__(self, x):
3 # self.val = x
4 # self.left = None
5 # self.right = None
6 class Solution:
7 def isSymmetrical(self, pRoot):
8 # write code here
9 if not pRoot:
10 return True
11 stack = [pRoot.left, pRoot.right]
12
13 while stack:
14 right = stack.pop() # 成对取出
15 left = stack.pop()
16 if left == None and right == None:
17 continue
18 if left == None or right == None:
19 return False
20 if left.val != right.val:
21 return False
22
23 # 成对插入
24 stack.append(left.left)
25 stack.append(right.right)
26 stack.append(left.right)
27 stack.append(right.left)
28
29 return True

bfs,队列实现

 1 # class TreeNode:
2 # def __init__(self, x):
3 # self.val = x
4 # self.left = None
5 # self.right = None
6 class Solution:
7 def isSymmetrical(self, pRoot):
8 # write code here
9 if not pRoot:
10 return True
11 queue = [pRoot.left, pRoot.right]
12
13 while queue:
14 left = queue.pop(0) # 成对取出
15 right = queue.pop(0)
16 if left == None and right == None:
17 continue
18 if left == None or right == None:
19 return False
20 if left.val != right.val:
21 return False
22
23 # 成对插入
24 queue.append(left.left)
25 queue.append(right.right)
26 queue.append(left.right)
27 queue.append(right.left)
28
29 return True

  

5. 把二叉树打印成多行

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

解:

层次遍历,bfs

 1 # class TreeNode:
2 # def __init__(self, x):
3 # self.val = x
4 # self.left = None
5 # self.right = None
6 class Solution:
7 # 返回二维列表[[1,2],[4,5]]
8 def Print(self, pRoot):
9 # write code here
10 if not pRoot:
11 return []
12 res = []
13 queue = [pRoot]
14 while queue:
15 tmp = []
16 for i in range(len(queue)):
17 node = queue.pop(0)
18 tmp.append(node.val)
19 if node.left:
20 queue.append(node.left)
21 if node.right:
22 queue.append(node.right)
23 if tmp:
24 res.append(tmp)
25 return res

  

dfs

 1 # class TreeNode:
2 # def __init__(self, x):
3 # self.val = x
4 # self.left = None
5 # self.right = None
6 class Solution:
7 # 返回二维列表[[1,2],[4,5]]
8 def Print(self, pRoot):
9 # write code here
10 if not pRoot:
11 return []
12 self.res = []
13
14 def helper(node, level):
15 if not node:
16 return
17 if level == len(self.res):
18 self.res.append([])
19 self.res[level].append(node.val)
20 if node.left:
21 helper(node.left, level + 1)
22 if node.right:
23 helper(node.right, level + 1)
24
25 helper(pRoot, 0)
26 return self.res

  

6. 按之字形顺序打印二叉树

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

解:

还是层次遍历,用一个 flag 控制每一层是正序还是逆序

 1 # class TreeNode:
2 # def __init__(self, x):
3 # self.val = x
4 # self.left = None
5 # self.right = None
6 class Solution:
7 def Print(self, pRoot):
8 # write code here
9 if not pRoot:
10 return []
11 leftToRight = True
12 queue = [pRoot]
13 res = []
14 while queue:
15 tmp = []
16 for i in range(len(queue)):
17 node = queue.pop(0)
18 tmp.append(node.val)
19 if node.left:
20 queue.append(node.left)
21 if node.right:
22 queue.append(node.right)
23 if tmp:
24 if leftToRight:
25 res.append(tmp)
26 else:
27 res.append(tmp[::-1])
28 leftToRight = not leftToRight
29 return res

7. 序列化二叉树

请实现两个函数,分别用来序列化和反序列化二叉树
二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。
二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
解:
这题的序列化就直接前序遍历实现即可,注意按要求用字符 # 和 !表示空节点和结束符。
主要问题在反序列化上,还是按照根左右的顺序递归,用 flag 来控制递归过程中,反序列化的节点值在数组中的索引,flag从0开始,每次都+1,遇到‘#’说明是空节点,不需要构造node
 1 # class TreeNode:
2 # def __init__(self, x):
3 # self.val = x
4 # self.left = None
5 # self.right = None
6 class Solution:
7 def __init__(self):
8 self.flag = -1
9 def Serialize(self, root):
10 # write code here
11 if not root:
12 return '#!'
13 return str(root.val)+'!'+self.Serialize(root.left)+self.Serialize(root.right)
14
15 def Deserialize(self, s):
16 # write code here
17 self.flag += 1
18 vals = s.split('!')
19 if self.flag >= len(vals):
20 return None
21 root = None
22 if vals[self.flag] != '#':
23 root = TreeNode(int(vals[self.flag]))
24 root.left = self.Deserialize(s)
25 root.right = self.Deserialize(s)
26 return root

8. 二叉搜索树的第k个节点

给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8)    中,按结点数值大小顺序第三小结点的值为4。

解:

中序遍历即有序

 1 # class TreeNode:
2 # def __init__(self, x):
3 # self.val = x
4 # self.left = None
5 # self.right = None
6 class Solution:
7 # 返回对应节点TreeNode
8 def KthNode(self, pRoot, k):
9 # write code here
10 if not pRoot:
11 return None
12 self.res = []
13 self.midOrdTrav(pRoot)
14 return self.res[k-1] if 0<k<=len(self.res) else None
15
16 def midOrdTrav(self, root):
17 if not root:
18 return
19 self.midOrdTrav(root.left)
20 self.res.append(root)
21 self.midOrdTrav(root.right)

  

中序遍历的时候维护一个计数器,到 k 个数了就返回

 1 # class TreeNode:
2 # def __init__(self, x):
3 # self.val = x
4 # self.left = None
5 # self.right = None
6 class Solution:
7 # 返回对应节点TreeNode
8 def KthNode(self, pRoot, k):
9 # write code here
10 if not pRoot:
11 return None
12
13 count = 0
14 stack = []
15 p = pRoot
16 while p or stack:
17 while p:
18 stack.append(p)
19 p = p.left
20 if stack:
21 p = stack.pop()
22 count += 1
23 if count == k:
24 return p
25 p = p.right
26 return None

 

 
9.数据流中的中位数
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
解:
维护两个堆,大顶堆用来存较小的数,从大到小排列;小顶堆用来存较大的数,从小到大排列。
保证小顶堆中的元素都大于等于大顶堆中的元素(始终保证较大数的那一半多一个或者一样多,中位数始终在这一边),所以 insert 的时候先 push 进小顶堆(存较大的数),再把小顶堆中的最小值 pop 出来 push 到大顶堆(存较小的数)中。
每次都检查,如果小顶堆的元素个数小于大顶堆的元素个数(较大的数比较小的数少了),就把大顶堆中的最大值 pop 出来 push 小顶堆。
取中位数的时候,如果当前两个堆一样多,显然是取小顶堆和大顶堆根结点的平均值;如果当前小顶堆元素个数多一个,显然是取小顶堆的根节点
 1 import heapq
2 class Solution:
3 def __init__(self):
4 self.small = [] # 小的数,大顶堆
5 self.large = [] # 大的数,小顶堆
6
7 def Insert(self, num):
8 # write code here
9 heapq.heappush(self.small, -heapq.heappushpop(self.large, num))
10 if len(self.large) < len(self.small):
11 heapq.heappush(self.large, -heapq.heappop(self.small))
12
13 def GetMedian(self, default=None):
14 # write code here
15 if len(self.large) > len(self.small):
16 return float(self.large[0])
17 return (self.large[0] - self.small[0])/2.

  

 
10. 重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
解:
其实就是一个递归的过程,每次找一下根节点在哪,进而定位好左右子树的切片,构建好了根节点之后再分别去构建左右子树
 1 # class TreeNode:
2 # def __init__(self, x):
3 # self.val = x
4 # self.left = None
5 # self.right = None
6 class Solution:
7 # 返回构造的TreeNode根节点
8 def reConstructBinaryTree(self, pre, tin):
9 # write code here
10 if not pre or not tin:
11 return None
12 root = TreeNode(pre[0])
13 index = self.Search(tin, root.val) # tin.index(root.val)
14 root.left = self.reConstructBinaryTree(pre[1:index+1], tin[:index])
15 root.right = self.reConstructBinaryTree(pre[index+1:], tin[index+1:])
16 return root
17
18 def Search(self, nums, target):
19 if not nums:
20 return -1
21 n = len(nums)
22 for i in range(n):
23 if nums[i] == target:
24 return i
25 return -1

剑指offer-二叉树的更多相关文章

  1. 剑指Offer——二叉树

    剑指Offer--二叉树 前言 数据结构通常是编程面试中考察的重点.在参加面试之前,应聘者需要熟练掌握链表.树.栈.队列和哈希表等数据结构,以及它们的操作.本片博文主要讲解二叉树操作的相关知识,主要包 ...

  2. 剑指offer 二叉树中和为某一个值的路径

    剑指offer 牛客网 二叉树中和为某一个值的路径 # -*- coding: utf-8 -*- """ Created on Tue Apr 9 15:53:58 2 ...

  3. 剑指offer 二叉树的层序遍历

    剑指offer 牛客网 二叉树的层序遍历 # -*- coding: utf-8 -*- """ Created on Tue Apr 9 09:33:16 2019 @ ...

  4. JS数据结构与算法 - 剑指offer二叉树算法题汇总

    ❗❗ 必看经验 在博主刷题期间,基本上是碰到一道二叉树就不会碰到一道就不会,有时候一个下午都在搞一道题,看别人解题思路就算能看懂,自己写就呵呵了.一气之下不刷了,改而先去把二叉树的基础算法给搞搞懂,然 ...

  5. 剑指offer——二叉树的镜像

    题目:操作给定的二叉树,将其变换为源二叉树的镜像. 思路:前序(根左右的顺序)遍历一棵树,在存储的时候将其左右树进行交换,最后按照处理后的树还原,即得到其镜像. /** public class Tr ...

  6. 剑指Offer 二叉树中和为某一值的路径(dfs)

    题目描述 输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径.路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径.     思路: 递归,然后深搜,因为题目定义的, ...

  7. 剑指Offer 二叉树的镜像

    题目描述 操作给定的二叉树,将其变换为源二叉树的镜像. 输入描述: 二叉树的镜像定义:源二叉树 8 / \ 6 10 / \ / \ 5 7 9 11 镜像二叉树 8 / \ 10 6 / \ / \ ...

  8. 剑指Offer——二叉树的下一个结点

    题目描述: 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回.注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针. 分析: 如果该结点存在右子树,那么返回右子树的最左结 ...

  9. 剑指Offer——二叉树的深度

    题目描述: 输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度. 分析: 二叉树的深度等于其左子树的深度和右子树的深度两个中最大的深 ...

  10. 剑指Offer——二叉树中和为某一值的路径

    题目描述: 输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径.路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径. 分析: 先序遍历二叉树,找到二叉树中结点值的和 ...

随机推荐

  1. Docker 镜像构建之 Dockerfile

    在 Docker 中创建镜像最常用的方式,就是使用 Dockerfile.Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明.官方文档:https://d ...

  2. 笔记-Linux 内存优化

    1.清理前内存使用情况 free -m2.开始清理 echo 1 > /proc/sys/vm/drop_caches 3.清理后内存使用情况 free -m 4.完成! 查看内存条数命令: d ...

  3. [BUUOJ记录] [CISCN 2019 初赛]Love Math & [NESTCTF 2019]Love Math 2

    主要考察利用已有函数构造危险函数绕过,实现RCE. 进入题目给出源码: <?php error_reporting(0); //听说你很喜欢数学,不知道你是否爱它胜过爱flag if(!isse ...

  4. cdq分治——bzoj2683简单题

    https://www.lydsy.com/JudgeOnline/problem.php?id=2683 知识点:1.以操作的顺序进行分治  2.cdq分治维护矩阵 3.计算比mid小的给比mid大 ...

  5. WebApi 接口传参接参

    阅读目录 一.get请求 1.基础类型参数 2.实体作为参数 3.数组作为参数 4.“怪异”的get请求 二.post请求 1.基础类型参数 2.实体作为参数 3.数组作为参数 4.后台发送请求参数的 ...

  6. Vue文件模板

    <template> <div> </div> </template> <script> export default { } </s ...

  7. ZK集群源码解读

    1.1. 集群模式 1.1.1.   数据同步总流程 1.1.1.1. OBSERVING 1.1.1.2. FOLLOWING 1.1.1.3. LEADING 1.1.2. 领导选举 1.1.2. ...

  8. 第一课、python基础学习笔记

    自动化非自动化的区别 自动化测试就是让机器按照人的想法把功能全部跑一遍 自动化测试的过程,让我们写一段程序去测试另一段程序是否正常的过程 Java 编译型语言,   编码-->编译-->解 ...

  9. flask提交表单验证不通过,以及CSRF攻击原理

    学习表单的问题1. 提交表单时怎么都无法验证通过 记录一下,自己的学习bug,主要是因为在模板中书写渲染的语句时,把CSRF的字段名写错了. 因为在模板中书写一些语句是没有提示的,自己手动敲代码容易出 ...

  10. 第24课 - #pragma 使用分析

    第24课 - #pragma 使用分析 1. #pragma简介 (1)#pragma 是一条预处理器指令 (2)#pragma 指令比较依赖于具体的编译器,在不同的编译器之间不具有可移植性,表现为两 ...