package BinaryTree
import (
"fmt"
"testing"
)
type Node struct {
Value int
Left *Node
Right *Node
}
/*
所有节点的指针只能往指,不能够形成环
二叉树先序、中序、后序遍历
先序:任何子树的处理顺序都是,先头节点、再左子树、然后右子树
中序:任何子树的处理顺序都是,先左子树、再头节点、然后右子树
后续:任何字数的处理顺序都是,先左子树、再右子树、然后头节点
1
2 3
4 5 6 7
先序:头左右,1 2 4 5 3 6 7
中序:左头右 4 2 5 1 6 3 7
后序:左右头 4 5 2 6 7 3 1
*/
func pre(head *Node) {
if head == nil {
return
}
fmt.Print(head.Value,"\t")
pre(head.Left)
pre(head.Right)
}
func in(head *Node) {
if head == nil {
return
}
in(head.Left)
fmt.Print(head.Value,"\t")
in(head.Right)
}
func pos(head *Node) {
if head == nil {
return
}
pos(head.Left)
pos(head.Right)
fmt.Print(head.Value,"\t")
}
func TestBinaryTree(t *testing.T) {
tree := &Node{
Value: 1,
Left: &Node{
Value: 2,
Left: &Node{
Value: 4,
},
Right: &Node{
Value: 5,
},
},
Right: &Node{
Value: 3,
Left: &Node{
Value: 6,
} ,
Right: &Node{
Value: 7,
},
},
}
pre(tree)
fmt.Println()
in(tree)
fmt.Println()
pos(tree)
fmt.Println()
}
// 递归遍历的本质:递归序
// 每一个节点都会到达三次
// 第一次到达时打印,先序
// 第二次到达时打印,中序
// 第三次达到时打印,后序
// 说明任何一个节点都可以到左树转一圈收集一些信息,到右树转一圈收集一些信息,还可以第三次回来做一些总结,这是树形dp的前提
// 递归方式实现二叉树的先序、中序、后序遍历
// 1.理解递归序
// 2.先序、中序、后序都可以在递归序的基础上加工出来
// 3.第一次到达一个节点就打印就是先序、第二次打印即中序、第三次即后序
func f(head *Node) {
if head == nil {
return
}
f(head.Left)
f(head.Right)
}
// 非递归方式实现二叉树的先序、中序、后序遍历
// 1.任何递归函数都可以改成非递归
// 2.自己设计压栈来实现
func preWithStack(head *Node) {
fmt.Println("pre-order")
stk := &stack{Elem: make([]*Node,0)}
stk.push(head)
for !stk.isEmpty() {
head = stk.pop()
fmt.Print(head.Value,"\t")
if head.Right != nil {
stk.push(head.Right)
}
if head.Left != nil {
stk.push(head.Left)
}
}
fmt.Println()
}
// 弹出打印
// 如有右孩子,就压入右
// 如有左孩子,就压入左
func posWithStack(head *Node) {
fmt.Println("pos-order")
stkPrint := &stack{Elem: make([]*Node,0)}
stk := &stack{Elem: make([]*Node,0)}
stk.push(head)
for !stk.isEmpty() {
head = stk.pop()
stkPrint.push(head)
if head.Left != nil {
stk.push(head.Left)
}
if head.Right != nil {
stk.push(head.Right)
}
}
for !stkPrint.isEmpty() {
fmt.Print(stkPrint.pop().Value,"\t")
}
fmt.Println()
}
// 弹出打印
// 如有左孩子,就压入左
// 如有右孩子,就压入右
func posWithStack2(head *Node) {
fmt.Println("pos-order")
if head == nil {
return
}
stk := &stack{Elem: make([]*Node,0)}
stk.push(head)
var c *Node
for !stk.isEmpty() {
c= stk.peek()
if c.Left != nil && head != c.Left && head != c.Right {
stk.push(c.Left)
}else if c.Right != nil && head != c.Right {
stk.push(c.Right)
}else {
fmt.Print(stk.pop().Value , "\t")
head = c
}
}
fmt.Println()
}
func inWithStack(head *Node) {
fmt.Println("in-order")
if head == nil {
return
}
stk := &stack{Elem: make([]*Node,0)}
for !stk.isEmpty() || head != nil {
if head != nil {
stk.push(head)
head = head.Left
}else {
head = stk.pop()
fmt.Print(head.Value,"\t")
head = head.Right
}
}
fmt.Println()
}
// 1.整条左边界依次入栈
// 2.1无法继续。弹出节点就打印,来到右子树上继续执行1
func TestBinaryTreeWithStack(t *testing.T) {
tree := &Node{
Value: 1,
Left: &Node{
Value: 2,
Left: &Node{
Value: 4,
},
Right: &Node{
Value: 5,
},
},
Right: &Node{
Value: 3,
Left: &Node{
Value: 6,
} ,
Right: &Node{
Value: 7,
},
},
}
preWithStack(tree)
posWithStack(tree)
posWithStack2(tree)
inWithStack(tree)
}
type stack struct {
Elem []*Node
}
func (s *stack)push(value *Node) {
s.Elem = append(s.Elem,value)
}
func (s *stack)pop() *Node {
res := s.Elem[len(s.Elem)-1]
s.Elem = s.Elem[:len(s.Elem)-1]
return res
}
func (s *stack)peek() *Node {
return s.Elem[len(s.Elem)-1]
}
func (s *stack)isEmpty() bool {
return len(s.Elem) == 0
}
/*
实现二叉树的按层遍历
1.其实就是宽度优先遍历,用队列 图的遍历需要加一个set
2.可以通过设置flag变量的方式,来发现某一层的结束
问题: 请你统计二叉树最大的宽度 (哪一层节点最多,有几个)
发现某一层开始,或结束
*/
func Level(head *Node) {
if head == nil {
return
}
qe := &queue{Elem: make([]*Node,0)}
qe.add(head)
for ! qe.isEmpty() {
cur := qe.poll()
fmt.Print(cur.Value,"\t")
if cur.Left != nil {
qe.add(cur.Left)
}
if cur.Right != nil {
qe.add(cur.Right)
}
}
fmt.Println()
}
func TestBinaryTreeLevel(t *testing.T) {
tree := &Node{
Value: 1,
Left: &Node{
Value: 2,
Left: &Node{
Value: 4,
},
Right: &Node{
Value: 5,
},
},
Right: &Node{
Value: 3,
Left: &Node{
Value: 6,
} ,
Right: &Node{
Value: 7,
},
},
}
Level(tree)
}
func maxWidthUseMap(head *Node) int {
if head == nil {
return 0
}
qe := &queue{Elem: make([]*Node,0)}
qe.add(head)
// key 在哪一层, value
levelMap := make(map[*Node]int)
levelMap[head] = 1
// 当前你正在统计哪一层的宽度,当前层的宽度是多少,一个节点出来的时候,再加上去,max 所有层的最大值
curLevel,curLevelNodes, max := 1, 0, 0
for !qe.isEmpty() {
cur := qe.poll()
curNodeLevel := levelMap[cur]
if cur.Left != nil { // 宽度优先遍历
levelMap[cur.Left] = curNodeLevel + 1
qe.add(cur.Left)
}
if cur.Right != nil { // 宽度优先遍历
levelMap[cur.Right] = curNodeLevel + 1
qe.add(cur.Right)
}
if curNodeLevel == curLevel { // 当前层的level 和统计层的level一样,说明该层没过期
curLevelNodes++
}else {
max = Max(max,curLevelNodes) // 不一致时统计上层
curLevel++
curLevelNodes = 1 // 新层到了
}
}
max = Max(max,curLevelNodes) //统计最后一层
return max
}
func maxWidthNoMap(head *Node) int {
if head == nil {
return 0
}
qe := &queue{Elem: make([]*Node,0)}
qe.add(head)
curEnd := head
var nextEnd *Node
max := 0
curlevelNodes := 0
for !qe.isEmpty() {
cur := qe.poll()
if cur.Left != nil {
qe.add(cur.Left)
nextEnd = cur.Left
}
if cur.Right != nil {
qe.add(cur.Right)
nextEnd = cur.Right
}
curlevelNodes++
if cur == curEnd {
max = Max(max,curlevelNodes)
curlevelNodes = 0
curEnd = nextEnd
}
}
return max
}
func TestMaxWidthUseMap(t *testing.T) {
tree := &Node{
Value: 1,
Left: &Node{
Value: 2,
Left: &Node{
Value: 4,
},
Right: &Node{
Value: 5,
},
},
Right: &Node{
Value: 3,
Left: &Node{
Value: 6,
} ,
Right: &Node{
Value: 7,
},
},
}
fmt.Println(maxWidthUseMap(tree))
fmt.Println(maxWidthNoMap(tree))
}
func Max(a,b int) int {
if a < b {
return b
}
return a
}
type queue struct {
Elem []*Node
}
func (q *queue)add(value *Node) { //非高效实现
q.Elem = append([]*Node{value},q.Elem...)
}
func (q *queue)poll() *Node {
res := q.Elem[len(q.Elem)-1]
q.Elem = q.Elem[:len(q.Elem)-1]
return res
}
func (q *queue)isEmpty() bool {
return len(q.Elem) == 0
}
/*
二叉树的序列化与反序列化
1.可以用先序或者中序或者后序或者按层遍历来实现二叉树的序列化
2.用了什么方式序列化,就用什么样的方式反序列化
树上玩KMP
题目
如何设计一个打印整棵树的函数
* *
/ \
* *
\ / \
* * *
----------------------------------------
* *
/ \ / \
* nil nil *
/ \ / \
nil * * *
*/
func pres(head *Node, ans *queue) {
if head == nil {
ans.add(nil)
}else {
ans.add(head)
pre(head.Left)
pre(head.Right)
}
}
func preb(prelist *queue) *Node {
head := prelist.poll()
if head == nil {
return nil
}
head.Left = preb(prelist)
head.Right = preb(prelist)
return head
}
// 按层序列化 实质就是广度优先遍历
func levelSerial(head *Node) *IntQueue {
ans := &IntQueue{Elem: make([]int,0)}
if head == nil {
ans.add(-999)
return ans
}
ans.add(head.Value)
qe := &queue{Elem: make([]*Node,0)}
qe.add(head)
for !qe.isEmpty() {
head = qe.poll()
if head.Left != nil {
ans.add(head.Left.Value)
qe.add(head.Left)
}else {
ans.add(-999)
}
if head.Right != nil {
ans.add(head.Right.Value)
qe.add(head.Right)
}else {
ans.add(-999)
}
}
return ans
}
func TestLevelSerial(t *testing.T) {
tree := &Node{
Value: 1,
Left: &Node{
Value: 2,
Left: &Node{
Value: 4,
},
Right: &Node{
Value: 5,
},
},
Right: &Node{
Value: 3,
Left: &Node{
Value: 6,
} ,
Right: &Node{
Value: 7,
},
},
}
fmt.Println(levelSerial(tree))
}
func buildByLevelQueue(levelList *IntQueue) *Node {
if levelList == nil || levelList.isEmpty() {
return nil
}
head := generateNode(levelList.poll())
qe := queue{Elem: make([]*Node,0)}
if head != nil {
qe.add(head)
}
var node *Node
for !qe.isEmpty() {
node = qe.poll()
node.Left = generateNode(levelList.poll())
node.Right = generateNode(levelList.poll())
if node.Left != nil {
qe.add(node.Left)
}
if node.Right != nil {
qe.add(node.Right)
}
}
return head
}
func generateNode(val int) *Node {
if val == -999 {
return nil
}
return &Node{Value: val}
}
func TestBuildByLevelQueue(t *testing.T) {
tree := &Node{
Value: 1,
Left: &Node{
Value: 2,
Left: &Node{
Value: 4,
},
Right: &Node{
Value: 5,
},
},
Right: &Node{
Value: 3,
Left: &Node{
Value: 6,
} ,
Right: &Node{
Value: 7,
},
},
}
pre(tree)
fmt.Println()
levelArr := levelSerial(tree)
fmt.Println(levelArr)
node := buildByLevelQueue(levelArr)
pre(node)
fmt.Println()
}
type IntQueue struct {
Elem []int
}
func NewIntQueue(arr []int) *IntQueue {
return &IntQueue{Elem: arr}
}
func (q *IntQueue)add(value int) { //非高效实现
q.Elem = append([]int{value},q.Elem...)
}
func (q *IntQueue)poll() int {
res := q.Elem[len(q.Elem)-1]
q.Elem = q.Elem[:len(q.Elem)-1]
return res
}
func (q *IntQueue)isEmpty() bool {
return len(q.Elem) == 0
}
/*
如何设计一个打印整棵树的打印函数
仁者见仁智者见智
*/
/*
二叉树结构如下定义
给你二叉树中的某个节点,返回该节点的后继节点
后继节点 中序遍历 某个节点的下一个节点
节点到他父亲节点的距离是k 时间复杂度做到O(k)
假设 x 有右子树 ,右子树上最左的节点一定是后继
x 没有右子树
*/
type Node1 struct {
value int
left *Node1
right *Node1
parent *Node1 //头节点的父指针 指向nil
}
//经典红黑树 每个节点就有三条指针
//递归序 时间复杂度O(N)
func getSuccessorNode(node *Node1) *Node1 {
if node == nil {
return node
}
if node.right != nil {
return getLeftMost(node.right)
}
// 无右子树
parent := node.parent
for parent != nil && parent.left != node { //当前节点时其父亲节点的右孩子
node = parent
parent = node.parent
}
return parent
}
func getLeftMost(node *Node1) *Node1 {
if node == nil {
return node
}
for node.left != nil {
node = node.left
}
return node
}
/*
前驱节点
*/
/*
题目
请把一段纸条竖着放在桌子上,然后从纸条的下边向上方对折一次,压出痕迹后展开。此时折痕是凹下去的,即折痕凸起的方向指向纸条的背面。如果从
纸条的下边向上方连续对折两次,压出折痕后展开,此时有三条折痕,从上到下一次是下折痕、下折痕和上折痕。
给定一个输入参数N,代表纸条都从下边向上方连续对折N次、请从上到下打印出所有这很大方向。
例如:N = 1 时,打印:down N = 2时,打印 down down up
*/
//递归过程,来到某一个节点
// i是节点的层数,N是一共的层数,down == true 凹 down == false 凸
func printAllFolds(N int) {
printProcess(1,N,true)
}
func printProcess(i,N int , down bool) {
if i > N {
return
}
printProcess(i+1, N, true)
fmt.Println(map[bool]string{down:"凹",!down:"凸"}[true])
printProcess(i+1,N,false)
}
func TestPrintAllFolds(t *testing.T) {
N := 3
printAllFolds(N)
}
/*
二叉树的递归套路
可以理解面试中绝大多数的二叉树问题,尤其是树型dp问题
本质是利用递归遍历二叉树的便利性
1. 假设以X节点为头,假设可以向X 左树和X 右树要任何信息
2. 在上一步的假设下, 讨论以X 为头节点的树, 得到答案的可能性(最重要 : 和X 有关 or 和X无关)
3. 列出所有的可能性后, 确定到底需要向左树和右树要什么样的信息
4. 把左树的信息和右树的信息求全集,就是任何一棵子树都需要返回的信息S
5. 递归函数都返回S,每一棵子树都这么要求
6. 写代码,在代码中考虑如何把左树的信息和右树的信息整合出整棵树的信息
X
/ \
Y Z
*/
/*
二叉树的递归套路深度实践
给定一棵二叉树的头节点head,返回这棵二叉树是不是平衡二叉树
每一棵子树左树高度和右树高度不超过1
*/
// 左右要求一样, info信息返回的结构体
type info struct {
isBalanced bool
height int
}
func isBalanced2(head *Node) bool { // 入口
return process2(head).isBalanced
}
func process2(X *Node) info {
if X == nil {
return info{
isBalanced: true,
height: 0,
}
}
leftInfo := process2(X.Left)
rightInfo := process2(X.Right)
height := Max(leftInfo.height,rightInfo.height) + 1 //左,右树高度最大的 + 头节点高度 就是整棵树的高度
isBalanced := true
if !leftInfo.isBalanced || !rightInfo.isBalanced || Abs(leftInfo.height - rightInfo.height) > 1 {
isBalanced = false
}
return info{
isBalanced: isBalanced,
height: height,
}
}
func Abs(n int) int {
if n < 0 {
return -n
}
return n
}
/*
二叉树的递归套路深度实践
给定一棵二叉树的头节点head,任何两个节点之间都存在距离,
返回整棵二叉树的最大距离
例如
A
/ \
B C
B 走到 C 需要三步
X
常见答案 即 和X 有关或无关
左 右
1. 和X 无关, 最大距离点 不通过X 最大距离是左树上的最大距离,or 右树上的最大距离 max(左,右)
2. 和X 有关, 最大距离通过X,X左树上最远的点,到X右树上最远的点, 即左树的高度, ---> 右树的高度
*/
type Info struct {
maxDistance int //整棵树的最大距离
height int //整棵树的高度
}
func maxDistance(head *Node) int {
return process(head).maxDistance
}
func process(X *Node) Info {
if X == nil {
return Info{0,0}
}
leftInfo := process(X.Left)
rightInfo := process(X.Right)
height := Max(leftInfo.height,rightInfo.height) + 1
maxDistance := Max(Max(leftInfo.maxDistance,rightInfo.maxDistance), leftInfo.height + rightInfo.height + 1 )
return Info{
maxDistance: maxDistance,
height: height,
}
}
/*
二叉树的递归套路深度实践
给定一棵二叉树的头节点head
返回这棵二叉树中最大的二叉搜索子树的节点树 、 头
搜索二叉树,整棵树上没有重复值
满足 左树比头小,右树比头大
X 无关 左 , 右 满足条件
X 有关 X为头 左树是BST, 右树是BST 左树最大值 < X 右树最小值 > X
*/
type MaxBSTInfo struct { // 左树是
IsAllBst bool
maxSubBSTSize int
max int
min int
}
func processBST(X *Node) *MaxBSTInfo {
if X == nil { //遇到空值 好设置就设置,不好设置赋值nil 后序人为判空
return nil
}
leftInfo := processBST(X.Left)
rightInfo := processBST(X.Right)
min, max, maxSubBSTSize := X.Value,X.Value, 0
if leftInfo != nil { //决策一下
min = Min(min,leftInfo.min)
max = Max(max,leftInfo.max)
maxSubBSTSize = Max(maxSubBSTSize,leftInfo.maxSubBSTSize)
}
if rightInfo != nil {
min = Min(min, rightInfo.min)
max = Max(max, rightInfo.max)
maxSubBSTSize = Max(maxSubBSTSize, rightInfo.maxSubBSTSize)
}
isAllBST := false
// 左树整体是搜索二叉树
if (leftInfo == nil || leftInfo.IsAllBst) &&
(rightInfo == nil || rightInfo.IsAllBst) &&
(leftInfo == nil || leftInfo.max < X.Value) &&
(rightInfo == nil || rightInfo.min > X.Value) {
isAllBST = true
if leftInfo != nil {
maxSubBSTSize += leftInfo.maxSubBSTSize
}
if rightInfo != nil {
maxSubBSTSize += rightInfo.maxSubBSTSize
}
maxSubBSTSize++ // 1是自己
}
return &MaxBSTInfo{
IsAllBst: isAllBST,
maxSubBSTSize: maxSubBSTSize,
max: max,
min: min,
}
}
func Min(a, b int) int {
if a > b {
return b
}
return a
}
/*
二叉树的递归套路深度实践
派对的最大快乐值
员工信息的定义如下
*/
type Employee struct { // 多叉树,不会有从下往上值的情况
happy int // 这名员工可以带来的快乐值
subordinates []Employee // 这名员工有哪些直接下级
}
/*
公司的每个员工都符合Employee类的描述。整个公司的人员结构可以看做是一棵标准的、没有环的多叉树。
树的头节点是公司唯一的老板。除老板之外的每个员工都有唯一的直接上级。叶节点是没有任何下属的基层员工(subordinates为空),除基层员工外,每个员工都有一个或多个直接下级。
这个公司现在要办party,你可以决定哪些员工来,哪些员工不来,规则:
1.如果某个员工来了,那么这个员工的所有直接下级都不能来
2.派对的整体快乐值是所有到场员工快乐值的累加
3.你的目标是让派对的整体快乐值尽量大
给定一棵多叉树的头节点boss,请返回派对的最大快乐值
X
/ | \
a b c
X 来跟不来
X来 : 一定能获得X自己快乐值 其每个下属不来的整棵树的最大快乐值
X不来: 0 + max(0, a.happy) + 0 + max(0, b.happy) + 0 + max(0, c.happy)
*/
type HappyInfo struct {
yes int //来的情况下
no int //不来的情况下
}
func processHappy(X Employee) HappyInfo { // 复杂度O(N)
if len(X.subordinates) == 0 { // base case 基层员工
return HappyInfo{
yes: X.happy,
no: 0,
}
}
yes, no := X.happy, 0
for _,next := range X.subordinates {
nextInfo := processHappy(next)
yes += nextInfo.no
no += Max(nextInfo.yes,nextInfo.no)
}
return HappyInfo{
yes: yes,
no: no,
}
}
/*
二叉树的递归套路深度实践
给定一棵二叉树的头节点head,返回这棵二叉树是不是满二叉树
满二叉树:每一层节点
高度L, 节点数N
满足 2 ^ L == N
高度和个数
*/
type FullBSInfo struct {
height int
nodes int
}
func processFullBs(X *Node) FullBSInfo {
if X == nil {
return FullBSInfo{}
}
leftInfo := processFullBs(X.Left)
rightInfo := processFullBs(X.Right)
height := Max(leftInfo.height , rightInfo.height) + 1
nodes := leftInfo.nodes + rightInfo.nodes + 1
return FullBSInfo{
height: height,
nodes: nodes,
}
}
func isFull(head *Node) bool {
if head == nil {
return true
}
all := processFullBs(head)
return (1 << all.height) == all.nodes
}
/*
二叉树的递归套路深度实践
给定一棵二叉树的头节点head
返回这棵二叉树中最大的二叉搜索树的头节点
X
X 无关 左 ,右 较大
X 有关 左大值 < X.value 右小值 > X.value
*/
type BstHeadInfo struct {
maxSubBSTHead *Node
maxSubBSTSize int
max int
min int
}
func processBstMaxHead(X *Node) *BstHeadInfo {
if X == nil {
return nil
}
leftInfo := processBstMaxHead(X.Left)
rightInfo := processBstMaxHead(X.Right)
min, max := X.Value, X.Value
var maxSubBSTHead *Node
maxSubBSTSize := 0
if leftInfo != nil {
min = Min(min,leftInfo.min)
max = Max(max,leftInfo.max)
maxSubBSTHead = leftInfo.maxSubBSTHead
maxSubBSTSize = leftInfo.maxSubBSTSize
}
if rightInfo != nil {
min = Min(min,rightInfo.min)
max = Max(max,rightInfo.max)
if rightInfo.maxSubBSTSize > leftInfo.maxSubBSTSize {
maxSubBSTHead = rightInfo.maxSubBSTHead
maxSubBSTSize = rightInfo.maxSubBSTSize
}
}
if leftInfo == nil || (leftInfo.maxSubBSTHead == X.Left && leftInfo.max < X.Value ) &&
rightInfo == nil || rightInfo.maxSubBSTHead == X.Right && rightInfo.min > X.Value{
maxSubBSTHead = X
if leftInfo != nil {
maxSubBSTSize += leftInfo.maxSubBSTSize
}
if rightInfo != nil {
maxSubBSTSize += rightInfo.maxSubBSTSize
}
maxSubBSTSize++
}
return &BstHeadInfo{
maxSubBSTHead: maxSubBSTHead,
maxSubBSTSize: maxSubBSTSize,
max: max,
min: min,
}
}
/*
后序
二叉树的递归套路深度实践
给定一棵二叉树的头节点head
返回这棵二叉树是不是完全二叉树
要么是满的,要么是从左往右变满的
宽度优先遍历
两种方法
1. 任何节点 有右无左,返回false, 否则继续
2. 一旦遇到,第一个左右孩子不双全的节点,后序遇到的所有节点都必须是叶节点
*
* *
* *
*/
type NodeIsCBT struct {
value int
left *NodeIsCBT
right *NodeIsCBT
}
func isCBT1(head *NodeIsCBT) bool {
if head == nil {
return true
}
queue := NewNodeIsCBTQueue()
leaf := false
var l, r *NodeIsCBT
queue.Add(head)
for !queue.IsEmpty() {
head = queue.Poll()
l = head.left
r = head.right
if (leaf && !(l == nil && r == nil)) || (l == nil && r != nil) {
return false
}
if l != nil {
queue.Add(l)
}
if r != nil {
queue.Add(r)
}
if l == nil || r == nil { //可能会被多次改成true
leaf = true
}
}
return true
}
type NodeIsCBTQueue struct {
Elem []*NodeIsCBT
}
func NewNodeIsCBTQueue() *NodeIsCBTQueue {
return &NodeIsCBTQueue{Elem: make([]*NodeIsCBT,0)}
}
func (n *NodeIsCBTQueue) IsEmpty() bool {
return len(n.Elem) == 0
}
func (n *NodeIsCBTQueue) Add(cbt *NodeIsCBT){
n.Elem = append([]*NodeIsCBT{cbt},n.Elem...)
}
func (n *NodeIsCBTQueue)Poll() *NodeIsCBT {
res := n.Elem[len(n.Elem)-1]
n.Elem = n.Elem[:len(n.Elem)-1]
return res
}
func (n *NodeIsCBTQueue)Peek() *NodeIsCBT {
return n.Elem[len(n.Elem)-1]
}
// 二叉树的递归套路
// 根据最后一个节点到哪了进行分类
// 1.满二叉树 无缺口
// 2. 有缺口, 缺口可能停在左树上
// 3.
// 4.
type InfoIsCBT struct {
isFull bool //是否是满二叉树
isCBT bool //是否是完全二叉树
height int //高度
}
func isCBT2(head *Node) bool {
if head == nil {
return true
}
return processInfoIsCBT(head).isCBT
}
func processInfoIsCBT(X *Node) *InfoIsCBT{
if X == nil {
return &InfoIsCBT{true,true,0}
}
leftInfo := processInfoIsCBT(X.Left)
rightInfo := processInfoIsCBT(X.Right)
height := Max(leftInfo.height,rightInfo.height) + 1
isFull := leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height
isCBT := false
if isFull {
isCBT = true
}else { //以X为头整棵树,不满
if leftInfo.isCBT && rightInfo.isCBT {
if leftInfo.isCBT && rightInfo.isFull && leftInfo.height == rightInfo.height + 1 {
isCBT = true
}
if leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height+1 {
isCBT = true //长满左树,没有撑到右树
}
if leftInfo.isFull && rightInfo.isCBT && leftInfo.height == rightInfo.height {
isCBT = true //最后一个节点侵入右树,并且把左树撑满
}
}
}
return &InfoIsCBT{isFull,isCBT,height}
}
/*
给定一棵二叉树的头节点head,和另外两个节点a和b
返回a和b的最低公共祖先
往上走,初次交汇的节点
*/
func lowestAncestor1(head,o1,o2 *Node) *Node { // o1, o2 一定在树上 O(N)
if head == nil {
return nil
}
parentMap := map[*Node]*Node{}
parentMap[head] = nil
fillParentMap(head,&parentMap)
o1Set := map[*Node]bool{}
cur := o1
o1Set[cur] = true
for parentMap[cur] != nil {
cur = parentMap[cur]
o1Set[cur] = true
}
cur = o2
_, ok := o1Set[cur]
for ok {
cur = parentMap[cur]
_, ok = o1Set[cur]
}
return cur
}
func fillParentMap(head *Node,parentMap *map[*Node]*Node) {
if head.Left != nil {
(*parentMap)[head.Left] = head
fillParentMap(head.Left,parentMap)
}
if head.Right != nil {
(*parentMap)[head.Right] = head
fillParentMap(head.Right,parentMap)
}
}
/*
o1,o2 无一个在x上
o1,o2 只一个在x上
o1,o2 都在x为头的树上
1. 左右各一个
2. 左o1,o2
3. 右o1,o2
4. x 自己是o1 或 o2
*/
type LowestAncestorInfo struct {
ans *Node
findO1 bool
findO2 bool
}
func lowestAncestor2(head, o1, o2 *Node) *Node {
return processLowestInfo(head,o1,o2).ans
}
func processLowestInfo(X, o1, o2 *Node) *LowestAncestorInfo {
if X == nil {
return &LowestAncestorInfo{nil, false, false}
}
leftInfo := processLowestInfo(X.Left,o1,o2)
rightInfo := processLowestInfo(X.Right,o1,o2)
findO1 := X == o1 || leftInfo.findO1 || rightInfo.findO1
findO2 := X == o2 || rightInfo.findO2 || rightInfo.findO2
//o1,o2 最初的交汇点在哪
var ans *Node
if leftInfo.ans != nil {
ans = leftInfo.ans
}
if rightInfo.ans != nil {
ans = rightInfo.ans
}
if ans == nil {
if findO1 && findO2 {
ans = X
}
}
return &LowestAncestorInfo{ans,findO1,findO2}
}
二叉树汇总及二叉树递归套路
于 2021-10-27 09:52:11 首次发布
本文详细介绍了二叉树的各种遍历方法,包括先序、中序、后序以及按层遍历,并展示了如何实现递归和非递归方式。此外,还探讨了二叉树的序列化与反序列化、平衡二叉树、最大搜索子树、最大距离计算等算法问题,深入剖析了二叉树的递归套路及其应用。
摘要由CSDN通过智能技术生成