Go语言实战案例-判断二叉树是否对称

简介: 本题要求判断二叉树是否对称,即左右子树镜像对称且对应节点值相等。可通过递归或迭代方法实现,常用于算法面试与树结构分析,具有较高实用价值。

 

给定一棵二叉树,判断这棵树是否是对称的。对称的含义是:这棵树的左子树和右子树在结构上是镜像对称的,且对应节点的值相等。

示例 1:

1
   / \
  2   2
 / \ / \
3  4 4  3
输出:true

示例 2:

1
   / \
  2   2
   \   \
   3    3
输出:false

二、应用场景

  • • 用户界面或布局中验证左右对称性
  • • 算法竞赛题目或笔试面试常考
  • • 树结构可视化或分析工具中,对称性判断用于简化处理

三、解题思路

本问题的关键在于:比较树的左子树和右子树是否镜像对称

我们可以采用两种方法:

方法一:递归判断

判断左右子树是否满足以下三个条件:

  1. 1. 左子树的左子树和右子树的右子树对称;
  2. 2. 左子树的右子树和右子树的左子树对称;
  3. 3. 当前两个节点值相同。

方法二:迭代判断(借助队列)

使用队列存储成对的节点,每次成对弹出并比较:

  • • 若都为空,继续;
  • • 若一个为空另一个不为空 → 不对称;
  • • 值不相等 → 不对称;
  • • 否则将子节点成对压入队列,继续判断。

四、Go语言实现

1. 数据结构定义

package main
import "fmt"
type TreeNode struct {
    Val   int
    Left  *TreeNode
    Right *TreeNode
}

2. 方法一:递归法

func isSymmetric(root *TreeNode) bool {
    if root == nil {
        return true
    }
    return isMirror(root.Left, root.Right)
}
func isMirror(left, right *TreeNode) bool {
    if left == nil && right == nil {
        return true
    }
    if left == nil || right == nil {
        return false
    }
    if left.Val != right.Val {
        return false
    }
    return isMirror(left.Left, right.Right) && isMirror(left.Right, right.Left)
}

3. 方法二:迭代法(使用队列)

func isSymmetricIterative(root *TreeNode) bool {
    if root == nil {
        return true
    }
    queue := []*TreeNode{root.Left, root.Right}
    for len(queue) > 0 {
        left := queue[0]
        right := queue[1]
        queue = queue[2:]
        if left == nil && right == nil {
            continue
        }
        if left == nil || right == nil || left.Val != right.Val {
            return false
        }
        queue = append(queue, left.Left, right.Right)
        queue = append(queue, left.Right, right.Left)
    }
    return true
}

五、测试样例

func main() {
    // 构建对称二叉树
    root := &TreeNode{Val: 1}
    root.Left = &TreeNode{Val: 2}
    root.Right = &TreeNode{Val: 2}
    root.Left.Left = &TreeNode{Val: 3}
    root.Left.Right = &TreeNode{Val: 4}
    root.Right.Left = &TreeNode{Val: 4}
    root.Right.Right = &TreeNode{Val: 3}
    fmt.Println("递归判断结果:", isSymmetric(root))           // true
    fmt.Println("迭代判断结果:", isSymmetricIterative(root)) // true
}

六、复杂度分析

方式 时间复杂度 空间复杂度
递归法 O(n) O(h)
迭代法 O(n) O(n)
  • • n 表示节点数量;
  • • h 表示树的高度(递归调用栈的深度);
  • • 迭代方法使用了队列,需要额外 O(n) 空间存储节点。

七、可视化理解

将二叉树从中心线对折,看左、右两部分是否完全重合,节点值是否相等。

镜像对称结构满足:

  • left.Left == right.Right
  • left.Right == right.Left

八、变种与扩展

  1. 1. 判断 N 叉树是否镜像对称:需要成对比较左右子节点;
  2. 2. 输出是否对称的最小修改操作:可结合动态规划思想;
  3. 3. 判断对称层级:例如仅判断前两层是否对称。

九、总结

内容 说明
核心判断条件 左右子树是否镜像结构,对应节点值是否相等
递归 vs 迭代 递归写法更直观,迭代适合大树或避免栈溢出
技巧点 左-右子树配对判断,使用队列模拟递归过程
实用价值 面试高频,掌握树结构对称性判断通用技巧

 

相关文章
|
2月前
|
Linux Go iOS开发
Go语言100个实战案例-进阶与部署篇:使用Go打包生成可执行文件
本文详解Go语言打包与跨平台编译技巧,涵盖`go build`命令、多平台构建、二进制优化及资源嵌入(embed),助你将项目编译为无依赖的独立可执行文件,轻松实现高效分发与部署。
|
3月前
|
数据采集 数据挖掘 测试技术
Go与Python爬虫实战对比:从开发效率到性能瓶颈的深度解析
本文对比了Python与Go在爬虫开发中的特点。Python凭借Scrapy等框架在开发效率和易用性上占优,适合快速开发与中小型项目;而Go凭借高并发和高性能优势,适用于大规模、长期运行的爬虫服务。文章通过代码示例和性能测试,分析了两者在并发能力、错误处理、部署维护等方面的差异,并探讨了未来融合发展的趋势。
321 0
|
2月前
|
存储 前端开发 JavaScript
Go语言实战案例-项目实战篇:编写一个轻量级在线聊天室
本文介绍如何用Go语言从零实现一个轻量级在线聊天室,基于WebSocket实现实时通信,支持多人消息广播。涵盖前后端开发、技术选型与功能扩展,助你掌握Go高并发与实时通信核心技术。
|
3月前
|
负载均衡 监控 Java
微服务稳定性三板斧:熔断、限流与负载均衡全面解析(附 Hystrix-Go 实战代码)
在微服务架构中,高可用与稳定性至关重要。本文详解熔断、限流与负载均衡三大关键技术,结合API网关与Hystrix-Go实战,帮助构建健壮、弹性的微服务系统。
457 1
微服务稳定性三板斧:熔断、限流与负载均衡全面解析(附 Hystrix-Go 实战代码)
|
3月前
|
安全 Go 开发者
Go语言实战案例:使用sync.Mutex实现资源加锁
在Go语言并发编程中,数据共享可能导致竞态条件,使用 `sync.Mutex` 可以有效避免这一问题。本文详细介绍了互斥锁的基本概念、加锁原理及实战应用,通过构建并发安全的计数器演示了加锁与未加锁的区别,并封装了一个线程安全的计数器结构。同时对比了Go中常见的同步机制,帮助开发者理解何时应使用 `Mutex` 及其注意事项。掌握 `Mutex` 是实现高效、安全并发编程的重要基础。
|
3月前
|
数据采集 Go API
Go语言实战案例:使用context控制协程取消
本文详解 Go 语言中 `context` 包的使用,通过实际案例演示如何利用 `context` 控制协程的生命周期,实现任务取消、超时控制及优雅退出,提升并发程序的稳定性与资源管理能力。
|
3月前
|
数据采集 Go API
Go语言实战案例:多协程并发下载网页内容
本文是《Go语言100个实战案例 · 网络与并发篇》第6篇,讲解如何使用 Goroutine 和 Channel 实现多协程并发抓取网页内容,提升网络请求效率。通过实战掌握高并发编程技巧,构建爬虫、内容聚合器等工具,涵盖 WaitGroup、超时控制、错误处理等核心知识点。
|
3月前
|
Go 开发者
Go语言实战案例:使用select监听多个channel
本文为《Go语言100个实战案例 · 网络与并发篇》第5篇,详解Go并发核心工具`select`的使用。通过实际案例讲解如何监听多个Channel、实现多任务处理、超时控制和非阻塞通信,帮助开发者掌握Go并发编程中的多路异步事件处理技巧。
|
1月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
156 1
|
3月前
|
Cloud Native 安全 Java
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
286 1