代码随想录day15 || 110 平衡二叉树,257 二叉树所有路径,404 左叶子之和,222 完全二叉树节点个数

110 平衡二叉树

// 计算平衡二叉树,定义,左右子树高度差不超过1,然后考虑计算高度,计算高度通常使用从叶子节点递归向上传递高度计算,也就是后续遍历的方式
func isBalanced(root *TreeNode) bool {
	// 思路 后续遍历同时求左右子树的高度,如果左右子树的高度差大于1,返回-1
	return !(getHigh(root) == -1)
}

func getHigh(root *TreeNode) int {
	// 根节点高度为0
	if root == nil {
		return 0
	}

	// 后序遍历计算高度
	//左
	left := getHigh(root.Left)
	if left == -1{
		return -1
	}

	//右
	right := getHigh(root.Right)
	if right == -1{
		return -1
	}

	// 根
	if left - right > 1 || right - left >  1{  // 如果高度差>1 返回-1
		return -1
	}
	var max int
	if left > right {
		max = left
	}else {
		max = right
	}
	return max+1  // 此时的根节点高度
}
// 时间复杂度 每个节点都遍历一次n  空间复杂度logn

257 二叉树所有路+

思路: 层序遍历最简单暴力求出每一层的节点,然后遍历每一层,strings.join(), 这样理论最大时间复杂度是2^0 * 2^1 ... 2^dep = 2^(0+1+2+...+dep) 非常复杂, 但是可以简化

func binaryTreePaths(root *TreeNode) []string {
	// 层序遍历
	q := list.New()
	q.PushBack(&NodePath{Node: root, Path: strconv.Itoa(root.Val)})
	var res []string
	for q.Len() > 0 {
		nodePath := q.Remove(q.Front()).(*NodePath)
		node := nodePath.Node
		path := nodePath.Path

		// 如果是叶子节点,保存路径
		if node.Left == nil && node.Right == nil {
			res = append(res, path)
		}

		// 如果有左子节点,加入队列并更新路径
		if node.Left != nil {
			newPath := join(path ,node.Left.Val)
			q.PushBack(&NodePath{Node: node.Left, Path: newPath})
		}

		// 如果有右子节点,加入队列并更新路径
		if node.Right != nil {
			newPath := join(path ,node.Right.Val)
			q.PushBack(&NodePath{Node: node.Right, Path: newPath})
		}
	}

	return res
}
type NodePath struct {
	Node *TreeNode
	Path string
}

func join(s1 string, i2 int) string {
	s2 := strconv.Itoa(i2)
	var s strings.Builder
	s.WriteString(s1)
	s.WriteString("->")
	s.WriteString(s2)
	return s.String()
}

func binaryTreePaths(root *TreeNode) []string {
	// 递归回溯算法

	var res = &[]string{}
	var q = &[]int{}
	traversal(root, res, q)
	return *res
}

func traversal(root *TreeNode, res *[]string, q *[]int) {
	// mid
	*q = append(*q, root.Val)
	if root.Left == nil && root.Right == nil {
		fmt.Println("nil")
		*res = append(*res, join(q))
	}


	// left
	if root.Left != nil {
		traversal(root.Left, res, q)
		*q = (*q)[0 : len(*q)-1] // 回溯移除最后一个节点
	}

	//right
	if root.Right != nil {
		traversal(root.Right, res, q)
		*q = (*q)[0 : len(*q)-1]
	}
}

func join(q *[]int) string {
	var res []string
	for _, i := range *q{
		s := strconv.Itoa(i)
		res = append(res, s)
	}
	return strings.Join(res, "->")
}

404 左 叶子 和

func sumOfLeftLeaves(root *TreeNode) int {
	// 最简单思路层序遍历,遇到左节点,返回
	var sum int
	q := list.New()
	q.PushBack(root)
	for q.Len() > 0 {
		node := q.Remove(q.Front()).(*TreeNode)
		if node.Left != nil {
			if node.Left.Left == nil && node.Left.Right == nil { // 判断叶子节点
				sum += node.Left.Val
			}
			q.PushBack(node.Left)
		}

		if node.Right != nil {
			q.PushBack(node.Right)
		}
	}

	return sum
}
时间n  空间n
func sumOfLeftLeaves(root *TreeNode) int {
	// 递归参数返回值,参数为节点,返回值为当前节点的左叶子和
	// 递归终止条件:如果节点为空,返回0
	if root == nil {
		return 0
	}

	// 初始化左子树和右子树的左叶子节点和
	leftSum := 0
	rightSum := 0

	// 如果左子节点存在并且是叶子节点,直接返回左子节点的值
	if root.Left != nil && root.Left.Left == nil && root.Left.Right == nil {
		leftSum = root.Left.Val
	} else {
		// 否则递归计算左子树的左叶子节点和
		leftSum = sumOfLeftLeaves(root.Left)
	}

	// 递归计算右子树的左叶子节点和
	rightSum = sumOfLeftLeaves(root.Right)

	// 返回左子树和右子树的左叶子节点和
	return leftSum + rightSum
}

222 完全二叉树节点个数

func countNodes(root *TreeNode) int {
	// 思路 遍历查数
	var res []int
	traversal(root, &res)
	return len(res)
}

func traversal(root *TreeNode, res *[]int) {
	if root == nil {
		return
	}
	*res = append(*res, root.Val)
	traversal(root.Left, res)
	traversal(root.Right, res)
}

func countNodes(root *TreeNode) int {
	// 利用满二叉树特性思路,题设完全二叉树,所以通过判断root是不是满二叉树,如果是直接2^n - 1, 如果不是,判断左右子节点,然后相加
	// 递归终止,判断为满二叉树
	if root == nil {
		return 0
	}
	var left, right int
	dep := checkFull(root)
	if dep == -1 { // 判断左子树是否是满二叉树
		left = countNodes(root.Left)
		right = countNodes(root.Right)
	}else{
		return int(math.Pow(2, float64(dep))) - 1
	}
	fmt.Println(root, left, right)
	return left + right + 1
}

// 判断是否是满二叉树,并且返回层数
func checkFull (root *TreeNode) int {
	if root == nil {
		return -1
	}
	if root.Left == nil && root.Right == nil {
		return 1
	}
	left := root.Left
	right := root.Right
	dep := 1
	for left != nil && right != nil{
		left = left.Left
		right = right.Right
		dep += 1
		if left == nil && right == nil { // 同时遍历到终点,说明是满二叉树
			return dep
		}
	}
	return -1 // 出现一侧节点不为空的情况,此时不是满二叉树
}

posted @ 2024-07-31 13:59  周公瑾55  阅读(11)  评论(0)    收藏  举报