程式碼隨想錄day14 || 226 翻轉二叉樹,101 對稱二叉樹, 104 二叉樹的最大深度, 111 二叉樹的最小深度

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

226 翻轉二叉樹

func invertTree(root *TreeNode) *TreeNode {
	// 思考,廣度優先遍歷,對於每一層,翻轉其左右子節點

	if root == nil {
		return nil
	}

	queue := list.New()
	queue.PushBack(root)
	size := 1 // 儲存每一層的節點個數
	for queue.Len() > 0{
		var count int
		for i:=0; i<size; i++{  // 彈出該層所有的節點
			node := queue.Remove(queue.Front()).(*TreeNode)

			// 將該節點的左右子節點翻轉
			if node.Left != nil || node.Right != nil {
				node.Left, node.Right = node.Right, node.Left
			}

			// 將翻轉後的子節點入佇列
			if node.Left != nil {
				queue.PushBack(node.Left)
				count++
			}
			if node.Right != nil {
				queue.PushBack(node.Right)
				count++
			}
		}
		size = count
	}
	return root
}
// list雙向連結串列實現的佇列,插入移除操作複雜度都是1
// 所以時間 遍歷翻轉每一個節點 n  空間 佇列 n

func invertTree(root *TreeNode) *TreeNode {  // 遞迴引數返回值
	// 遞迴前序遍歷
	if root == nil {  // 遞迴終止條件
		return nil
	}

	// 交換左右子節點
	if root.Left != nil || root.Right != nil {  // 單次遞迴邏輯
		root.Left, root.Right = root.Right, root.Left
	}
	invertTree(root.Left)
	invertTree(root.Right)
	return root
}
// 時間複雜度n  空間 如果平衡二叉樹logn  如果連結串列 n
// 遞迴前序後序遍歷都可以直觀理解,但是中序時候,需要特殊處理遞迴邏輯,因為先一步遞迴左子樹之後,處理完交換邏輯左子樹變成了右子樹,此時往下執行交換右子樹就是錯誤的,所以之後的邏輯應該改成仍然互動左子樹

101 判斷二叉樹對稱

func isSymmetric(root *TreeNode) bool {
	// 遞迴
	if root == nil {
		return true
	}

	return symmetric(root.Left, root.Right)
}

func symmetric(left, right *TreeNode) bool { // 遞迴引數返回值

	// 遞迴終止條件
	if left == nil && right != nil ||
		left != nil && right == nil ||
		left != nil && right != nil && left.Val != right.Val {
		// 左空右非空 || 左非空右邊空 || 左右數值不相等
		return false
	}

	if left == nil && right == nil {
		return true
	}

	// 最後一種情況,左右非空並且值相等
	// 遞迴邏輯
	inner := symmetric(left.Left, right.Right)
	outer := symmetric(left.Right, right.Left)
	return inner && outer
}

時間,每個節點遍歷一次 n 空間logn

104 最大深度

image

func maxDepth(root *TreeNode) int {
	// 考慮層序遍歷
	if root == nil {
		return 0
	}

	queue := list.New()
	queue.PushBack(root)
	dep := 1
	size := 1
	for queue.Len() >0{
		var count int
		for i:=0; i<size; i++ {
			node := queue.Remove(queue.Front()).(*TreeNode)

			if node.Left != nil {
				queue.PushBack(node.Left)
				count++
			}

			if node.Right != nil {
				queue.PushBack(node.Right)
				count++
			}
		}
		if count == 0{
			return dep
		}
		size = count
		dep++

	}
	return dep
}
// 層序遍歷每個節點遍歷一次,時間n 空間 佇列長度最長為n/2 = n

func maxDepth(root *TreeNode) int {
	// 遞迴方法,深度優先遍歷,因為需要不斷傳遞子節點高度給父節點,所以考慮後續遍歷,同時根節點高度就是樹的深度
	if root == nil {
		return 0
	}

	left := maxDepth(root.Left)
	right := maxDepth(root.Right)
	var res int = right
	if left > right {
		res = left
	}
	return res+1
}

111 最小深度

func minDepth(root *TreeNode) int {
	// 思考層序遍歷,終止條件是左右子樹都是空
	if root == nil {
		return 0
	}

	queue := list.New()
	queue.PushBack(root)
	dep := 1
	size := 1
	for queue.Len() >0 {
		var count int
		for i := 0; i < size; i++ {
			node := queue.Remove(queue.Front()).(*TreeNode)

			if node.Left == nil && node.Right == nil {
				return dep
			}

			if node.Left != nil {
				queue.PushBack(node.Left)
				count++
			}

			if node.Right != nil {
				queue.PushBack(node.Right)
				count++
			}
		}
		size = count
		dep++
	}
	return dep
}
// 層序遍歷每個節點遍歷一次,時間n 空間 佇列長度最長為n/2 = n

func minDepth(root *TreeNode) int {
	// 遞迴方法,深度優先遍歷,最小深度,終止條件是遇到無葉子的子節點,從上往下傳遞,中左右前序遍歷
	if root == nil {
		return 0
	}

	// 如果左子樹為空,遞迴右子樹
	if root.Left == nil {
		return minDepth(root.Right) + 1
	}

	// 如果右子樹為空,遞迴左子樹
	if root.Right == nil {
		return minDepth(root.Left) + 1
	}

	// 左右子樹都不為空,返回左右子樹的最小深度
	leftDepth := minDepth(root.Left)
	rightDepth := minDepth(root.Right)
	return int(math.Min(float64(leftDepth), float64(rightDepth))) + 1
}

相關文章