LintCode解题记录 17.5.3

Tips: 忙着改毕业论文,忙着完成导师布置的任务,只能自己偷偷的在晚上的时候刷题- -
最近主要做了一下二叉顺序树的相关题目,题目总体难度一般。

LintCode 661 Convert BST to Greater Tree
虽然是Easy难度的题,但还是很有新意的:D,稍微思考了一下,树相关的题目一定是和递归紧紧联系在一起的,所以这道题就是从最右的叶子节点开始遍历,按照右子树、根节点、左子树这样的方式遍历,同时开了一个sum变量,统计遍历到某个节点时的值。

    int sum = 0;
    TreeNode* convertBST(TreeNode* root) {
        // Write your code here
        if (NULL == root) return NULL;
        root->right = convertBST(root->right);
        root->val += sum;
        sum = root->val;
        root->left = convertBST(root->left);
        return root;
    }

LintCode 85 Insert Node in a Binary Search Tree
往二元顺序树里插入一个值为val的节点。递归的方式就不说了,这里Challenge里提到能否以非递归的形式实现呢?奈何愚笨,想了半天都没做对。问题主要是出在 最后要返回这个二叉树的根节点。
先看我的错误版本:思路是这样的,首先把最初的root存起来,然后循环去寻找该插入的点,直到root == NULL。然后在该地方新建一个节点,最后返回初始的根节点。看起来美滋滋,可惜错啦!

    TreeNode* insertNode(TreeNode* root, TreeNode* node) {
        // write your code here
        TreeNode *tmp = root;
        while (root){
            if (node->val < root->val) root = root->left;
            else root = root->right;
        }
        root = new TreeNode(node->val);
        return tmp;
    }

这种方法的问题就在于没有无法保存连接关系。比如往节点A的左子树插入一节点,如果A节点的左子树为空,A = A->left,然后在 new TreeNode()在此新建一个节点,是无法让 A->left == this new TreeNode。而解决这一问题的办法就是用A->left = new TreeNode()来代替。这样就可以保证连接关系。

    TreeNode* insertNode(TreeNode* root, TreeNode* node) {
        // write your code here
        if (NULL == node) return root;
        TreeNode *ret = new TreeNode(node->val);
        if (NULL == root) return ret;
        TreeNode *tmp = root;
        while (tmp){
            if (node->val < tmp->val){
                if (NULL == tmp->left){
                    tmp->left = node;
                    return root;
                }
                tmp = tmp->left;
            }else{
                if (NULL == tmp->right){
                    tmp->right = ret;
                    return root;
                }
                tmp = tmp->right;
            }
        }
    }

LintCode 11 Search Range in Binary Search Tree
返回二叉树内节点值在k1到k2之间的所有值。二叉顺序树内的一个重要的性质就是 中序遍历是 递增序列。题目要求要返回满足要求的递增序列,所以只需要中序遍历一次二元查找树即可。当然还可以加一些遍历条件,让其减少递归的次数。

     vector<int> ans;
     void dfs(TreeNode *root, int k1, int k2)
     {
         if (NULL == root) return;
         dfs(root->left, k1, k2);
         if (root->val >= k1 && root->val <= k2) ans.push_back(root->val);
         dfs(root->right, k1, k2);
     }
    vector<int> searchRange(TreeNode* root, int k1, int k2) {
        // write your code here
        ans.clear();
        dfs(root, k1, k2);
        //sort(ans.begin(), ans.end());
        return ans;
    }

LintCode 95 Validate Binary Search Tree
判断一棵给定的二叉树是不是二元查找树。利用性质:二元查找树的中序遍历是递增数列(充要条件)。中序遍历一次给定树,然后判断该vector的后一个元素是不是永远>前一个元素。这里说一个细节:顺序容器的size函数返回的是一个unsigned int,即如果遍历该vector时写成这样for (int i = 0; i < v.size()-1; i++)是有问题的,即当v.size()==0时,系统计算v.size()-1 = -1 => 由于unsigned int 是非负的,所以会把-1转成max(long long)好像是42亿多。。所以推荐写成for (int i =1; i < v.size(); i++)这样的形式。

    vector<int> ans;
    void inorder(TreeNode *root)
    {
        if (NULL == root) return;
        inorder(root->left);
        ans.push_back(root->val);
        inorder(root->right);
    }
    bool isValidBST(TreeNode *root) {
        // write your code here
        //二元查找树的中序遍历是一个递增数列
        ans.clear();
        inorder(root);
        for (int i = 1; i < ans.size(); i++){
            if (ans[i] <= ans[i-1]) return false;
        }
        return true;
    }

LintCode 86 Binary Search Tree Iteration
Challenge:Extra memory usage O(h), h is the height of the tree.
Super Star: Extra memory usage O(1).
正常思路:用一个vector和一个int指针分别来存储中序遍历的值和当前所指的值。但是这种方法的空间复杂度为O(n),n是节点个数。题目要求是O(h),也就是O(logn),所以这个肯定是不对的。
后来上网搜了一下,发现要用堆栈可以满足O(logn),也是是考察非递归形式的中序遍历。这种迭代的写法很多面试会考到,是bugfree.

    stack<TreeNode*> s;
    BSTIterator(TreeNode *root) {
        // write your code here
        while (root){
            s.push(root);
            root = root->left;
        }
    }

    //@return: True if there has next node, or false
    bool hasNext() {
        // write your code here
        return s.size() > 0;
    }

    //@return: return next node
    TreeNode* next() {
        // write your code here
        TreeNode *tmp = s.top();
        s.pop();
        TreeNode* res = tmp;
        tmp = tmp->right;
        while (tmp){
            s.push(tmp);
            tmp = tmp->left;
        }
        return res;
    }

LintCode 87 Remove Node in Binary Tree
删除二叉查找树中的某一个值为val的节点,先递归的find,然后找到之后删除。删除主要要考虑这么几种情况:
1.如果要删除的节点是叶子节点,那么直接删除。
2.如果是有单个孩子的节点,那么把他的孩子节点放到该位置上即可。
3.如果是双孩子节点,那么需要把 他左孩子的最大节点或者是右孩子的最小节点 放到该位置上,然后删掉那么 左孩子的最大节点或者最大节点(因为这些节点肯定是 孩子节点或者单孩子节点)。

    int findMaxInLeft(TreeNode* root){
        if (!root->right) return root->val;
        else return findMaxInLeft(root->right);
    }
    TreeNode* removeNode(TreeNode* root, int value) {
        // write your code here
        if (NULL == root) return NULL;
        if (value > root->val){
            root->right = removeNode(root->right, value);
        }else if (value < root->val){
            root->left = removeNode(root->left, value);
        }else{
            //find the node needed to be removed.
            if (!root->left && !root->right){
                //leaf node
                //free(root);// or root = NULL;
                root = NULL;
            }else if (root->left && !root->right){
                TreeNode *q = root;
                root = root->left;
                free(q);
            }else if (!root->left && root->right){
                TreeNode *q = root;
                root = root->right;
                free(q);
            }else{
                int val = findMaxInLeft(root->left);
                root = removeNode(root, val);
                root->val = val;
            }
        }
        return root;
    }

总结:重点掌握 二元查找树的非递归插值方法、非递归的三种遍历方法。当然二元查找树是很简单的一部分,由此扩展,至少要掌握 avl树的插入节点与删除操作,以及常见的B-tree,B+tree,R-tree的基本概念和应用。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值