算法设计与分析第四次作业

#99.Recover Binary Search Tree

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

Example 1:
Input: [1,3,null,null,2]
   1
  /
 3
  \
   2
Output: [3,1,null,null,2]
   3
  /
 1
  \
   2
Example 2:
Input: [3,1,4,null,null,2]
  3
 / \
1   4
   /
  2
Output: [2,1,4,null,null,3]
  2
 / \
1   4
   /
  3

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

这道题如果用O(n)的空间复杂度是很简单的,直接进行一次中序遍历就好了,所以这题的难点其实在于如何用O(1)的空间复杂度来遍历一个二叉树,老实说一开始我是没有什么思路的,因为无论是用递归还是非递归的方法其空间复杂度都会达到O(n),在查询相关资料后我发现了一种叫做Morris Traversal的方法,其基本思路就是虽然遍历不能改变树的结构,但是只是对最终状态有要求,所以可以在中间加入一些边然后删掉恢复原状态就好了。所以可以利用线索二叉树,让中序遍历的前驱节点指向下一个节点,然后在合适的时候删掉就好了。

具体算法描述如下:

  1. 如果当前节点的左孩子为空,则输出当前节点并将其右孩子作为当前节点。

  2. 如果当前节点的左孩子不为空,在当前节点的左子树中找到当前节点在中序遍历下的前驱节点。

    a) 如果前驱节点的右孩子为空,将它的右孩子设置为当前节点。当前节点更新为当前节点的左孩子。

    b) 如果前驱节点的右孩子为当前节点,将它的右孩子重新设为空(恢复树的形状)。输出当前节点。当前节点更新为当前节点的右孩子。

用以上算法就可以实现一个O(1)空间复杂度的中序遍历,然后我们回到这题本身,有两个节点的值被互换了,一个正常的搜索二叉树中序遍历结果是递增的,我们假设为 a 1 a_1 a1 a 2 a_2 a2 a n a_n an,交换会出现两种情况,一种是两个节点相邻,也就是变成 a 1 a 2 a_1a_2 a1a2 a k a k − 1 a_ka_{k-1} akak1 a n a_n an, 也有可能两个节点不相邻,也就是变成 a 1 a 2 ⋯ a m a k + 1 ⋯ a m − 1 a k ⋯ a n a_1a_2 \cdots a_ma_{k+1}{\cdots}a_{m-1}a_k{\cdots}a_n a1a2amak+1am1akan,第一种情况出现了一个序列下降,也就是 a k a_k ak a k − 1 a_{k-1} ak1, 第二种出现了两种序列下降,也就是 a m a_m am a k + 1 a_{k+1} ak+1 a m − 1 a_{m-1} am1 a k a_k ak,这两种情况其实可以归为一种,交换第一个发现降序对的前驱节点和最后一个降序对的后继节点,所以具体代码如下:

class Solution {
public:
    void recoverTree(TreeNode* root) {
        TreeNode* cur = root;
        first = NULL;
        second = NULL;
        pre = NULL;
        while(cur){
            TreeNode* next;
            if(cur->left == NULL){
                next = cur->right;
                check(pre,cur);
                pre = cur;
            }
            else{
                TreeNode* prev = cur->left;
                while(prev->right && prev->right != cur){
                    prev = prev->right;
                }
                if(prev->right){
                    next = cur->right;
                    prev->right = NULL;
                    check(pre,cur);
                    pre = cur;
                }
                else{
                    prev->right = cur;
                    next = cur->left;
                }
            }
            cur = next;
        }
        swap();
    }
private:
    void check(TreeNode* pre, TreeNode* cur){
        if(pre && pre->val > cur->val){
            if(!first){
                first = pre;
            }
            second = cur;
        }
    }
    void swap(){
        int tmp = first->val;
        first->val = second->val;
        second->val = tmp;
    }
    TreeNode* first;
    TreeNode* second;
    TreeNode* pre;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
国科大的算法设计与分析相关1-5章复习题 第一章样例: 1.讲义习题一: 第1(执行步改为关键操作数)、第2、3、6、7题 习题一 1答:执行步4pmn+3pm+2m+1;关键操作2n*m*p 2方法一答:2n-2次 方法二答:2n-2次 3 1)证明:任给c,n>c,则10n2>cn 。不存在c使10n22c时,logn>c,从而n2logn>=cn2,同上。 6 答:logn,n2/3,20n,4n2,3n,n! 7 答:1)6+n 2) 3)任意n 2.讲义习题二:第5题。 答:c、e是割点。每点的DFN、L值:A1,1、B2,1、C3,1、D4,4、E5,1、F6,5、G7,5。最大连通分支CD、EFG、ABCE。 3.考虑下述选择排序算法: 输入:n个不等的整数的数组A[1..n] 输出:按递增次序排序的A For i:=1 to n-1 For j:=i+1 to n If A[j]<A[i] then A[i] A[j] 问:(1)最坏情况下做多少次比较运算?答1+2+..+n-1=n(n-1)/2 (2)最坏情况下做多少次交换运算?在什么输入时发生? n(n-1)/2,每次比较都交换,交换次数n(n-1)/2。 4.考虑下面的每对函数f(n)和g(n) ,比较他们的阶。 (1) f(n)=(n2-n)/2, g(n)=6n (2)f(n)=n+2 , g(n)=n2 (3)f(n)=n+nlogn, g(n)=n (4)f(n)=log(n!), g(n)= 答:(1)g(n)=O(f(n)) (2)f(n)=O(g(n) (3)f(n)=O(g(n) (4)f(n)=O(g(n) 5.在表中填入true或false . 答案: f(n) g(n) f(n)=O(g(n) f(n)=(g(n)) f(n)=(g(n)) 1 2n3+3n 100n2+2n+100 F T F 2 50n+logn 10n+loglogn T T T 3 50nlogn 10nloglogn F T F 4 logn Log2n T F F 5 n! 5n F T F 6.用迭代法求解下列递推方程: (1) (2) ,n=2k 答:(1)T(n)=T(n-1)+n-1=T(n-2)+n-2+n-1 =…=T(1)+1+2+…+n-1=n(n-1)/2=O(n2) (2)T(n)=2T(n/2)+n-1=2(2T(n/4)+n/2-1)+n-1 =4T(n/4)+n-2+n-1=4(2T(n/23)+n/4-1)+n-2+n-1 =23T(n/23)+n-4+n-2+n-1

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值