leetcode刷题|【LeetCode】NO.226.翻转二叉树的一次负负得正还能AC的调试画图分析
前言 前几天朋友在群里发了张图:简单来说,负负得正
文章图片
当时感觉挺好笑的,结果今天就被我碰上了。
LeetCode.NO.226.翻转二叉树
Given the root of a binary tree, invert the tree, and return its root.
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/invert-binary-tree
文章图片
想好一会儿,给了一种很烦的递归思路:
void Swap(struct TreeNode* root)
{struct TreeNode* tmp = root->left;
root->left = root->right;
root->right = tmp;
}
void _invertTree(struct TreeNode* root, struct TreeNode* left, struct TreeNode* right)
{if(left == NULL && right == NULL)
{return;
}
if(left != NULL && right != NULL)
{_invertTree(left, left->left, left->right);
_invertTree(right, right->left, right-> right);
Swap(root);
}
if(left == NULL && right != NULL)
{_invertTree(right, right->left, right-> right);
Swap(root);
}
//上一句结束后,进行了一次Swap,left不是变成right,right不是变成left了?那下面的if应该执行下去!?
if(left != NULL && right == NULL)
{_invertTree(left, left->left, left->right);
Swap(root);
}
}struct TreeNode* invertTree(struct TreeNode* root)
{if(root == NULL)
return root;
_invertTree(root, root->left, root->right);
return root;
}
提交之后,过了
但是又看了看,看出了问题:
if(left == NULL && right != NULL)
{_invertTree(right, right->left, right-> right);
Swap(root);
}
//上一句结束后,left不是变成right,right不是变成left了?那下面的if应该执行下去!?
if(left != NULL && right == NULL)
{_invertTree(left, left->left, left->right);
Swap(root);
}
第一次Swap,left不是变成right,right不是变成left了?那下面的if还应该执行下去!?可是我们应该让这次递归结束,不能再去交换了啊!!但是他错误地交换了之后,为什么还能AC???
理应这么写,每次Swap后,return跳出当前递归
if(left == NULL && right != NULL)
{_invertTree(right, right->left, right-> right);
Swap(root);
return;
}
if(left != NULL && right == NULL)
{_invertTree(left, left->left, left->right);
Swap(root);
}
我怎么也看不出来,为什么没return还能过。
研究过程 我们打开VS,只能自己写好测试用例,调试!!!
【leetcode刷题|【LeetCode】NO.226.翻转二叉树的一次负负得正还能AC的调试画图分析】测试用例长这样:
文章图片
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
typedef struct BTNode
{ struct BTNode* right;
struct BTNode* left;
int val;
}BTNode;
BTNode* BTNodeCreate(int x)
{ BTNode* root = (BTNode*)malloc(sizeof(BTNode));
root->val = x;
root->left = NULL;
root->right = NULL;
return root;
}void Swap(struct BTNode* root)
{struct BTNode* tmp = root->left;
root->left = root->right;
root->right = tmp;
}
void _invertTree(struct BTNode* root, struct BTNode* left, struct BTNode* right)
{if (left == NULL && right == NULL)
{return;
}
if (left != NULL && right != NULL)
{_invertTree(left, left->left, left->right);
_invertTree(right, right->left, right->right);
Swap(root);
}
if (left == NULL && right != NULL)
{_invertTree(right, right->left, right->right);
Swap(root);
}
if (left != NULL && right == NULL)
{_invertTree(left, left->left, left->right);
Swap(root);
}
}struct BTNode* invertTree(struct BTNode* root)
{if (root == NULL)
return root;
_invertTree(root, root->left, root->right);
return root;
}
int main()
{ BTNode* node1 = BTNodeCreate(1);
BTNode* node2 = BTNodeCreate(2);
BTNode* node3 = BTNodeCreate(3);
node1->right = node2;
node2->right = node3;
invertTree(node1);
return 0;
}
再把这段有异议的代码拿出来:
if (left == NULL && right != NULL)
{_invertTree(right, right->left, right->right);
Swap(root);
}
/*位置1*/
if (left != NULL && right == NULL)
{_invertTree(left, left->left, left->right);
Swap(root);
}
我们在位置1处停下。
那么按照我的理解,此时:
left == val为3的节点监视:
right == NULL
root->left == val为3的节点
root->right == NULL
文章图片
root->left 和 root->right 确实交换了,但left和right没有交换!!!
原来问题出在这里:
left 和 right 是一份root->left 和 root->right的临时拷贝,root->left和root-right确实交换了,但身为临时拷贝的left和right还是没交换,该是谁就还是谁!所以下面 if 语句根本就不会进去!本题优化解答 这个递归写的有点长,因为又用了一个子函数
_invertTree
,我们试着不用子函数来做一下,让代码少一点struct TreeNode* invertTree(struct TreeNode* root){if(!root)
return NULL;
struct TreeNode* left = root->left;
struct TreeNode* right = root->right;
root->right = invertTree(left);
root->left = invertTree(right);
return root;
}
简单说明以下,递归,简单来说就是两个字——分治以下是递归展开图,测试用例依然是上面那个[1,null,2,null,3]
本题想要翻转一棵二叉树,那么,我们可以先翻转左子树和右子树;
对于左子树,我们可以先翻转左子树的左子树和左子树的右子树
对于右子树,我们可以先翻转右子树的左子树和右子树的右子树
… … … …
文章图片
总结 好了,总结一波
- 发现可疑问题并且眼睛看看不出来的时候,调试!
- 脑子不够用,比如递归的时候脑子一层一层展开真的不够用时候,画图!画递归展开图!
推荐阅读
- 宽容谁
- 我要做大厨
- 增长黑客的海盗法则
- 画画吗()
- 2019-02-13——今天谈梦想()
- 远去的风筝
- 三十年后的广场舞大爷
- 叙述作文
- 20190302|20190302 复盘翻盘
- 学无止境,人生还很长