Loading

[LeetCode] 101. Symmetric Tree(对称的树)

Description

Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).

给一棵二叉树,判断它是否是自身的镜像(也就是关于 root 轴对称)

For example, this binary tree [1, 2, 2, 3, 4, 4, 3] is symmetric:

例如,二叉树 [1, 2, 2, 3, 4, 4, 3] 是对称的:

    1
   / \
  2   2
 / \ / \
3  4 4  3

But the following [1, 2, 2, null, 3, null, 3] is not:

但二叉树 [1, 2, 2, null, 3, null, 3] 不是:

    1
   / \
  2   2
   \   \
   3    3

Follow up

Solve it both recursively and iteratively.

以迭代和递归两种方法解决。

Solution

迭代解法:层序遍历

如果一棵二叉树是左右对称的,那么其每一层节点的排布也应该是左右对称的。可以通过层序遍历找出每一层的所有节点,再检查这个节点列表是不是对称的。需要注意的是,层序遍历的时候,null 节点也是需要被考虑进去的,这样当树的层级过深时会有 MLE 的风险(特别是层级很深的稀疏树,一层下来大部分节点都是 null,占据无意义的空间。实际上我第一次提交就爆了内存)。问题出在层序遍历时往下扩张的过程,如果一个节点本身为 null,那就没有必要继续往下扩展了,这样可以节约大量内存,代码如下:

/**
 * Example:
 * var ti = TreeNode(5)
 * var v = ti.`val`
 * Definition for a binary tree node.
 * class TreeNode(var `val`: Int) {
 *     var left: TreeNode? = null
 *     var right: TreeNode? = null
 * }
 */
import java.util.*

class Solution {
    fun isSymmetric(root: TreeNode?): Boolean {
        if (root == null) {
            return true
        }
        val queue: Queue<TreeNode?> = LinkedList()
        queue.offer(root)

        while (queue.isNotEmpty()) {
            val size = queue.size
            val values = arrayListOf<Int?>()

            for (i in 1..size) {
                val node = queue.poll()
                values.add(node?.`val`)
                // 只对非 null 的节点进行扩展
                node?.let {
                    queue.offer(it.left)
                    queue.offer(it.right)
                }
            }

            if (values.all { it == null }) {
                break
            }

            if (!values.isSymmetric()) {
                return false
            }
        }

        return true
    }

    private fun List<Int?>.isSymmetric(): Boolean {
        if (this.size < 2) {
            return true
        }
        var left = 0
        var right = this.lastIndex
        while (left < right) {
            if (this[left] != this[right]) {
                return false
            }
            left++
            right--
        }
        return true
    }
}

递归解法(来自 discussion):

判断一个树是否镜像,则需要判断其左右子树是否能够通过翻转变化相等。这样就有和比较两棵树是否相等类似了,只不过递归调用的过程中,我们判断的是 left.rightright.left 以及 left.leftright.right 这两组是否相等,代码如下:

/**
 * Example:
 * var ti = TreeNode(5)
 * var v = ti.`val`
 * Definition for a binary tree node.
 * class TreeNode(var `val`: Int) {
 *     var left: TreeNode? = null
 *     var right: TreeNode? = null
 * }
 */
class Solution {
    fun isSymmetric(root: TreeNode?): Boolean {
        return root == null || isSymmetric(root.left, root.right)
    }

    private fun isSymmetric(left: TreeNode?, right: TreeNode?): Boolean {
        if (left == null || right == null) {
            return left == right
        }
        if (left.`val` != right.`val`) {
            return false
        }
        return isSymmetric(left.left, right.right) && isSymmetric(left.right, right.left)
    }
}
posted @ 2020-10-16 10:46  Zhongju.copy()  阅读(93)  评论(0编辑  收藏  举报