程式碼隨想錄day15 || 110 平衡二叉樹,257 二叉樹所有路徑,404 左葉子之和,222 完全二叉樹節點個數

周公瑾55發表於2024-07-31

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 // 出現一側節點不為空的情況,此時不是滿二叉樹
}

相關文章