LintCode解题记录 17.5.3

来源:互联网 发布:漫威宇宙实力排行知乎 编辑:程序博客网 时间:2024/04/30 18:26

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
原创粉丝点击