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. 基于Nodejs的sequelize操纵数据库

    ## 使用基于ORM架构的sequelize操纵数据库 ### 1.技术背景 ```Sequelize是一个基于promise的关系型数据库ORM框架,*********************技术文 ...

  2. Redis高可用——副本机制

    目录 概念 配置 同步方式 起点 主从握手 部分同步 完全同步 执行完全同步判断条件 完全同步代码实现 为实现Redis服务的高可用,Redis官方为我们提供了副本机制(或称主从复制)和哨兵机制.副本 ...

  3. eclipse android程序运行报错:Conversion to Dalvik format failed: Unable to execute dex:

    [2013-06-19 16:59:01 - Dex Loader] Unable to execute dex: Multiple dex files define Landroid/support ...

  4. 为什么 list(range) 比 [i for i in range()] 快?

    为什么 list(range) 比 [i for i in range()] 快? t0 = time.time() list(range(100000)) print(time.time()-t0) ...

  5. 4-6年经验左右、优秀的 Java 程序员应该具备的技能

    4-6年经验左右.优秀的 Java 程序员应该具备的技能有哪些,按“专业技能”和“项目”两块,包括但不限于以下内容. 专业节能方面 基础:JDK 常用类的原理.源码.使用场景. 设计模式:常用几种的原 ...

  6. 算法专题 | 10行代码实现的最短路算法——Bellman-ford与SPFA

    今天是算法数据结构专题的第33篇文章,我们一起来聊聊最短路问题. 最短路问题也属于图论算法之一,解决的是在一张有向图当中点与点之间的最短距离问题.最短路算法有很多,比较常用的有bellman-ford ...

  7. 前后端API交互如何保证数据安全性?

    前言 前后端分离的开发方式,我们以接口为标准来进行推动,定义好接口,各自开发自己的功能,最后进行联调整合.无论是开发原生的APP还是webapp还是PC端的软件,只要是前后端分离的模式,就避免不了调用 ...

  8. Dos简易基础及常用Dos命令

    Dos简易基础及常用Dos命令 什么是cmd? cmd是command的缩写,意指操作系统中的命令行程序,一般说的都是Windows中的Dos系统. 如何打开cmd? 键盘操作:Win + R 输入c ...

  9. Q200510-02-02: 重复的DNA序列 SQL解法

    重复的DNA序列所有 DNA 都由一系列缩写为 A,C,G 和 T 的核苷酸组成,例如:“ACGAATTCCG”.在研究 DNA 时,识别 DNA 中的重复序列有时会对研究非常有帮助. 编写一个函数来 ...

  10. nginx -s reload 导致的错误

    C:\pleiades\nginx-1.16.1_3\nginx-1.16.1>nginx -s reload nginx: [error] CreateFile() "C:\plei ...