[LeetCode] Recover Binary Search Tree 解题报告

Two elements of a binary search tree (BST) are swapped by mistake.
Recover the tree without changing its structure.

Note:
A solution using O(n) space is pretty straight forward. Could you devise a constant space solution?

confused what  "{1,#,2,3}" means?  > read more on how binary tree is serialized on OJ.

» Solve this problem

[解题报告]
O(n)空间的解法比较直观,中序遍历一遍以后,重新赋值一遍即可,这个解法可以面向n个元素错位的情况。但是对于O(1)空间的解法,最开始的想法是,可以考虑采用类似最大堆的调正过程的算法,但是这样又可能会破坏树的原有结构。暂未想出来解法。

只能给个O(n)空间的解法。

[Code]

1:    void recoverTree(TreeNode *root) {  
2: // Start typing your C/C++ solution below
3: // DO NOT write int main() function
4: vector<TreeNode*> list;
5: vector<int > vals;
6: InOrderTravel(root, list, vals);
7: sort(vals.begin(), vals.end());
8: for(int i =0; i< list.size(); i++)
9: {
10: list[i]->val = vals[i];
11: }
12: }
13: void InOrderTravel(TreeNode* node, vector<TreeNode*>& list, vector<int>& vals)
14: {
15: if(node == NULL) return;
16: InOrderTravel(node->left, list, vals);
17: list.push_back(node);
18: vals.push_back(node->val);
19: InOrderTravel(node->right, list, vals);
20: }

Updates:  3/16/2013
Searched in the web. Actually, there is a smart solution to travel the tree with two node.
The link is http://discuss.leetcode.com/questions/272/recover-binary-search-tree

1:  void Solution::recoverTree(TreeNode *h) {  
2: TreeNode *f1=NULL, *f2=NULL;
3: bool found = false;
4: TreeNode *pre, *par = 0; // previous AND parent
5: while(h) { // Morris Traversal
6: if(h->left == 0) {
7: if(par && par->val > h->val) { // inorder previous is: par
8: if(!found) {
9: f1 = par;
10: found = true;
11: }
12: f2 = h;
13: }
14: par = h;
15: h = h->right;
16: continue;
17: }
18: pre = h->left;
19: while(pre->right != 0 && pre->right != h)
20: pre = pre->right;
21: if(pre->right == 0) {
22: pre->right = h;
23: h = h->left;
24: } else {
25: pre->right = 0;
26: if(pre->val > h->val) { // inorder previous is: pre
27: if(!found) {
28: f1 = pre;
29: found =true;
30: }
31: f2 = h;
32: }
33: par = h;
34: h = h->right;
35: }
36: }
37: if(found)
38: swap(f1->val, f2->val);
39: }

Update: 3/21/2013  上一个解法不容易看清楚,添加分析。
O(1)的解法就是
Inorder traverse, keep the previous tree node,
Find first misplaced node by
if ( current.val < prev.val )
   Node first = prev;

Find second by
if ( current.val < prev.val )
   Node second = current;

After traversal, swap the values of first and second node. Only need two pointers, prev and current node. O(1) space.

但是这个解法的前提是Traverse Tree without Stack. 中序遍历如何才能不使用栈。这里就要引入一个概念, Threaded Binary Tree。So, we first create links to Inorder successor and print the data using these links, and finally revert the changes to restore original tree.

1. Initialize current as root 
2. While current is not NULL
If current does not have left child
a) Print current’s data
b) Go to the right, i.e., current = current->right
Else
a) Make current as right child of the rightmost node in current's left subtree
b) Go to this left child, i.e., current = current->left

代码如下:

/* Function to traverse binary tree without recursion and without stack */
vector < int > inorderTraversal( TreeNode * root )
{
       vector < int > result;  
       TreeNode   *current,*pre;
       if ( root == NULL )
       return result;
       current = root ;
       while (current != NULL )
       {                
             if (current->left == NULL )
             {
                    result.push_back(current->val);
                    current = current->right;     
             }   
             else
             {
                    /* Find the inorder predecessor of current */
                    pre = current->left;
                    while (pre->right != NULL && pre->right != current)
                           pre = pre->right;
                    /* Make current as right child of its inorder predecessor */
                    if (pre->right == NULL )
                    {
                           pre->right = current;
                           current = current->left;
                    }
                   
                    /* Revert the changes made in if part to restore the original
                 tree i.e., fix the right child of predecssor */   
                    else
                    {
                           pre->right = NULL ;
                           result.push_back(current->val);
                           current = current->right;     
                    } /* End of if condition pre->right == NULL */
             } /* End of if condition current->left == NULL*/
       } /* End of while */
       return result;
}

那么,基于这个双指针遍历,可以把错置节点的判断逻辑加进去,就可以完美的在O(1)空间内,完成树的重构。

[Code]
改动代码如红字所示。增加了一个pointer — parent来记录上一个访问节点。整个遍历过程中,使用(parent->val > current->val)来寻找违规节点,但是区别是,要获取第一次violation的parent和第二次violation的current,然后交换。

void  recoverTree(TreeNode *root)
{     
       TreeNode *f1=NULL, *f2=NULL;
       TreeNode  *current,*pre, *parent=NULL;
       if (root == NULL)
             return ;
       bool found = false ;
       current = root;
       while (current != NULL)
       {                
             if (current->left == NULL)
             {
                    if(parent && parent->val > current->val)
                    {
                           if(!found)
                           {
                                 f1 = parent;
                                 found = true;
                           }
                           f2 = current;
                    }
                    parent = current;
                    current = current->right;     
             }   
             else
             {
                    /* Find the inorder predecessor of current */
                    pre = current->left;
                    while (pre->right != NULL && pre->right != current)
                           pre = pre->right;
                    /* Make current as right child of its inorder predecessor */
                    if (pre->right == NULL)
                    {
                           pre->right = current;
                           current = current->left;
                    }
                    /* Revert the changes made in if part to restore the original
                    tree i.e., fix the right child of predecssor */   
                    else
                    {
                           pre->right = NULL;
                           if(parent->val > current->val)
                           {
                                 if(!found)
                                 {
                                        f1 = parent;       
                                        found = true;
                                 }
                                 f2 = current;
                           }
                           parent = current;
                           current = current->right;     
                    } /* End of if condition pre->right == NULL */
             } /* End of if condition current->left == NULL*/
       } /* End of while */
       if (f1 && f2)
             swap(f1->val, f2->val);
}
以下是对提供的参考资料的总结,按照要求结构化多个要点分条输出: 4G/5G无线网络优化与网规案例分析: NSA站点下终端掉4G问题:部分用户反馈NSA终端频繁掉4G,主要因终端主动发起SCGfail导致。分析显示,在信号较好的环境下,终端可能因节能、过热保护等原因主动释放连接。解决方案建议终端侧进行分析处理,尝试关闭节电开关等。 RSSI算法识别天馈遮挡:通过计算RSSI平均值及差值识别天馈遮挡,差值大于3dB则认定有遮挡。不同设备分组规则不同,如64T和32T。此方法可有效帮助现场人员识别因环境变化引起的网络问题。 5G 160M组网小区CA不生效:某5G站点开启100M+60M CA功能后,测试发现UE无法正常使用CA功能。问题原因在于CA频点集标识配置错误,修正后测试正常。 5G网络优化与策略: CCE映射方式优化:针对诺基亚站点覆盖农村区域,通过优化CCE资源映射方式(交织、非交织),提升RRC连接建立成功率和无线接通率。非交织方式相比交织方式有显著提升。 5G AAU两扇区组网:与三扇区组网相比,AAU两扇区组网在RSRP、SINR、下载速率和上传速率上表现不同,需根据具体场景选择适合的组网方式。 5G语音解决方案:包括沿用4G语音解决方案、EPS Fallback方案和VoNR方案。不同方案适用于不同的5G组网策略,如NSA和SA,并影响语音连续性和网络覆盖。 4G网络优化与资源利用: 4G室分设备利旧:面对4G网络投资压减与资源需求矛盾,提出利旧多维度调优策略,包括资源整合、统筹调配既有资源,以满足新增需求和提质增效。 宏站RRU设备1托N射灯:针对5G深度覆盖需求,研究使用宏站AAU结合1托N射灯方案,快速便捷地开通5G站点,提升深度覆盖能力。 基站与流程管理: 爱立信LTE基站邻区添加流程:未提供具体内容,但通常涉及邻区规划、参数配置、测试验证等步骤,以确保基站间顺畅切换和覆盖连续性。 网络规划与策略: 新高铁跨海大桥覆盖方案试点:虽未提供详细内容,但可推测涉及高铁跨海大桥区域的4G/5G网络覆盖规划,需考虑信号穿透、移动性管理、网络容量等因素。 总结: 提供的参考资料涵盖了4G/5G无线网络优化、网规案例分析、网络优化策略、资源利用、基站管理等多个方面。 通过具体案例分析,展示了无线网络优化中的常见问题及解决方案,如NSA终端掉4G、RSSI识别天馈遮挡、CA不生效等。 强调了5G网络优化与策略的重要性,包括CCE映射方式优化、5G语音解决方案、AAU扇区组网选择等。 提出了4G网络优化与资源利用的策略,如室分设备利旧、宏站RRU设备1托N射灯等。 基站与流程管理方面,提到了爱立信LTE基站邻区添加流程,但未给出具体细节。 新高铁跨海大桥覆盖方案试点展示了特殊场景下的网络规划需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值