LeetCode之路:226. Invert Binary Tree

一、引言

这道题的 Trivia 栏目下的信息还是挺有意思的:

Google: 90% of our engineers use the software you wrote (Homebrew), but you can’t invert a binary tree on a whiteboard so fuck off.

这句话的意思我就不翻译了(^_^),可以自己去百度翻译或者有道划词看哦。

还是贴上题干信息吧:

Invert a binary tree.

原二叉树

to

变化后的二叉树

其实一看二叉树的逆置,我的内心是痛苦的:

大学的时候学习《数据结构》这门课的时候,对于二叉树的回忆实在是太惨了。

但是既然走上了刷题的道路,那么不管是再难再不想做的题,我们也要迎难而上。

那么,这道题该怎么做呢?

二、柳暗花明又一村:编程中的印象画派

我曾经在之前的 LeetCode 之路的系列博客之中,有重点讨论过递归算法:

如果把编程比作画画,那么递归函数就是当之无愧的印象画派;

我们凑近了去看,往往被它粗糙的用墨放荡的线条所迷乱;

而当我们放弃对其上下求索,端一杯咖啡悠闲品味的时候,却在不经意间看到了它给我们勾勒出的那一幅绚烂的意境;

这就是我所理解的递归。

想要了解这篇博客的同学可以点击这里 LeetCode之路:104. Maximum Depth of Binary Tree

其实这道题我思考过两次:

第一次我看到这道题,我想了很久,应该如何一步一步的交换左右节点呢?那就从叶子节点开始交换,交换了两个叶子节点之后,我们又继续来交换叶子节点的父节点…如此这般,越想越觉得复杂;

第二次看到这道题的时候,是正好 IDE 打开太慢,打开 LeetCode 想打发下时间的时候,突然就飘过来一个想法:

其实我根本不需要看的那么细,我只需要从根节点开始,交换两个紧挨着的子节点即可,只是这两个子节点一定要是已经处理过(各自的子节点已经交换过了)的子节点即可

这个想法袭来,顿时那种递归算法带来的印象画派的那种全局尽在掌握的感觉油然而生,那么其实代码的编写,就只需要注意下退出的条件即可:

当前节点若为空指针,无需进行交换处理,则退出本次递归

当前节点的左子节点若不为空,则对左子节点进行交换子节点处理

当前节点的右子节点若不为空,则对右子节点进行交换子节点处理

当前节点的左右子节点的子节点都各自处理完成后,交换当前节点的左右子节点

按照这个逻辑,我写下了如下的代码:

// my solution , runtime = 3 ms
class Solution {
public:
    void invertLeftRight(TreeNode *node) {
        if (node == nullptr) return;
        if (node->left != nullptr) invertLeftRight(node->left);
        if (node->right != nullptr) invertLeftRight(node->right);
        swap(node->left, node->right);
    }

    TreeNode* invertTree(TreeNode *root) {
        invertLeftRight(root);
        return root;
    }
};

按照上述的分析逻辑,写出上述的代码其实不难,但是这段代码总给我一种冗余的感觉,因为套用了两个函数,这里肯定需要简化。

三、最高票答案:简化的美

这里简化的方法,恕我实在没有思考出来,这里附上最高票答案:

// perfect solution , runtime = 3 ms
class Solution {
public:
    TreeNode* invertTree(TreeNode *root) {
        if (root) {
            invertTree(root->left);
            invertTree(root->right);
            swap(root->left, root->right);
        }
        return root;
    }
};

这里,我乍一看到这个代码的时候,我第一反应就是:

每一次递归只要当前节点不为空,不就要返回一个 root 吗,那得返回多少个 root 啊?

其实这也是我一直未能成功简化代码的原因。

其实这里我的思维出现了一个很大的漏洞,那就是:

当第一层级的 root->left 执行结束后,root->left 的所有子孙节点都已经完成了交换;

同理 root->right 执行结束后,root->right 的所有子孙节点都完成了交换;

并且在前面这两个步骤里,我们并没有对 invertTree 函数的返回值进行处理;

直到我们交换完最后一对子节点后,才唯一返回了一个 root 值。

其实这一个思维漏洞真的很容易扰乱我的思维,总把迭代看成遍历思考,然后想着遍历 N 次 invertTree 函数怎么也得返回 N 次 root 值,那么这 N 次的 root 值都去哪里了呢?

其实 N - 1 次都在 :

invertTree(root->left);
invertTree(root->right);

中默认未处理丢弃掉了。

三、总结

这是一道比较简单的题目,本人也在递归的方法下,就仅仅花了 3 分钟而已。

但是思维漏洞还是有的,代码还不够简洁。

五一回来后的第一道题,难免觉得有点手生,再接再厉吧!

To be Stronger!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值