二叉树汇总及二叉树递归套路

本文详细介绍了二叉树的各种遍历方法,包括先序、中序、后序以及按层遍历,并展示了如何实现递归和非递归方式。此外,还探讨了二叉树的序列化与反序列化、平衡二叉树、最大搜索子树、最大距离计算等算法问题,深入剖析了二叉树的递归套路及其应用。
摘要由CSDN通过智能技术生成
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}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

metabit

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

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

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

打赏作者

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

抵扣说明:

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

余额充值