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](https://img2024.cnblogs.com/blog/2426371/202407/2426371-20240730114454814-1256914858.png)
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
}