【努力刷力扣】第二十一天 --- 迭代法中序先序重整二叉树
引言:全部算法建立在无重复点的基础上
本人初次尝试写博客,希望各位看官大佬多多包容
有错误希望巨巨们提出来,我一定会及时改正,谢谢大家
在自己最好的年纪,找到了未来的目标
还有1年奋斗刷题,明年去面试实习,加油!
<该题的另一种递归解法见我另一篇博客>
递归重整二叉树
题外话:
这个类型的题目十分重要,非常多的大厂愿意考,所以说这道题是重中之重,非常锻炼思维,所以有共同目标的友友们一定要练好此题,加油,冲冲冲!
老样子,先看看题目要求:
简单分划重组二叉树
矛盾点
正常向左添加节点都没问题,但是我不到什么时候加到右节点,又该把该节点加到谁的右边!这就是设计迭代算法最大的矛盾之处!
前序知识:
1、先序遍历可以把每个节点理解成一个个根节点,但是具体连到左还是右不能明确(个人理解)。中根遍历就是疯狂向左走,所以可以理解成从当前节点疯狂左走可以到的最左的节点(个人理解)。这二者可以用开始的时候理解,先序第一个节点必定是根,他疯狂左走到的边界一定是中根第一个节点,那么这段范围就是全都连在左边的范围(后面有图印证)
2、(最重要的来了)对于前序遍历中的任意两个连续节点 u 和 v,根据前序遍历的流程,我们可以知道 u 和 v 只有两种可能的关系:
1)v 是 u 的左儿子。这是因为在遍历到 u 之后,下一个遍历的节点就是 u 的左儿子,即 v;
2)u 没有左儿子,并且 v 是 u 的某个祖先节点(或者 u 本身)的右儿子。如果 u 没有左儿子,那么下一个遍历的节点就是 u 的右儿子。如果 u 没有右儿子,我们就会向上回溯,直到遇到第一个有右儿子的节点。
整体迭代思路:
1、根据矛盾点以及前序知识,那我们就针对性的设置一个专用栈空间(因为中序和先序本质上得到的是相反的),存储可能连有右儿子的所有节点,初始时将根节点压入。我们需要知道我每次从当前节点疯狂向左走最多到谁那里,根据中序的特点,可以根据初始的时候理解,所以初始值赋值为0。
2、这些节点都有可能连右节点,所以入专门的栈,一旦发现当前栈顶是最左边界了,就说明现在这个节点就该连在某个节点右面。
3、因为中根遍历走到最左后回溯,如果你发现每次回溯的值(即将专用指针右移得到的值)和栈顶一样,说明二者单线连,因为栈里面的元素就是这样单线向左连下来的
4、一旦找到了不同说明出现了不同,回溯的时候走岔了路,就把最后弹出来的节点右面连上该节点,把该节点入栈,以为她也有权利拥有右节点
5、重复上述2-4过程。
具体分析
力扣官方题解
这道题官方题解写的很好,有完整的模拟流程,这里我引用一下,嘻嘻嘻。
代码
注:这是大体思路,具体写的时候找个简单的例子,一边模拟一边写,很简单就有了,再多找复杂例子验证即可。
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if (preorder.size() == 0) {//特殊情况判断
return nullptr;
}
TreeNode* root = new TreeNode(preorder.front());//初始化
stack<TreeNode*> can_link_right;//专有栈
can_link_right.push(root);
int index = 0;//初始化
for (int i = 1; i < preorder.size(); i++) {
TreeNode* item = new TreeNode(preorder[i]);
if (can_link_right.top()->val != inorder[index]) {//没有走到当前节点下左边界
can_link_right.top()->left = item;
can_link_right.push(item);
}
else {//走到左边界,那就要找当前节点是栈里面谁的右节点
TreeNode* temp = nullptr;
while (can_link_right.size() != 0 && can_link_right.top()->val == inorder[index]) {
temp = can_link_right.top();
can_link_right.pop();
index++;
}
temp->right = item;
can_link_right.push(item);
}
}
return root;
}
};
(所有代码均已在力扣上运行无误)
经测试,该代码运行情况是(经过多次测试所得最短时间):
时间复杂度:O(n),其中 n是树中的节点个数。
Sum Up
1、先找常规思路解法,发现不行(处理不了右节点),找到矛盾点,针对矛盾点进行编程优化处理,就可得到最优解,博主就是这个解题历程。