我的leetcode学习之旅第二周——第一部分 二叉树中的分治法与遍历法 Divide Conquer & Traversal

1、学习大纲——二叉树

二叉树( Binary Tree )问题的考点剖析:
1、第一类考察形态:求值,求路径类二叉树问题
2、第二类考察形态:结构变化类二叉树问题
3、第三类考察形态:二叉查找树( Binary Search Tree )类问题:非递归( Non recursion or Iteration )版本的中序遍历 Inorder Traversal

2、典型题

1、求值:一般就是求最大、最小、平均、求和、路径等等。都是在树的路径上操作。

给一棵二叉树,找到有最大平均值的子树。返回子树的根结点。

/**
* 本参考程序来自九章算法,由 @九章算法 提供。版权所有,转发请注明出处。
/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right>;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right> = NULL;
 *     }
 * }
 */
 //定义一个类 ResultType 作为输出结果
class ResultType {
public:
    int sum, size;
    ResultType():sum(0), size(0) {}
    ResultType(int _sum, int _size): sum(_sum), size(_size) {}
};

class Solution {
public:
    /**
     * @param root the root of binary tree
     * @return the root of the maximum average of subtree 
     */
    TreeNode* findSubtree2(TreeNode* root) {
        // Write your code here
        helper(root);
        return node;
    }

    ResultType helper(TreeNode* root) {
        if (root == NULL) {
            return ResultType();
        }
        ResultType left = helper(root->left);
        ResultType right = helper(root->right);
        
        ResultType result = ResultType(left.sum + right.sum + root->val,
                                       left.size + right.size + 1);
		// 这里把除法转为了乘法,我猜是可以避免浮点数的计算
        if (node == NULL || result.sum * data.size >= data.sum * result.size) {
            data = result;
            node = root;
        }

        return result;
    }

private:
    TreeNode* node = NULL;   //存储当前最优节点
    ResultType data;         //存储当前最优结果
};

给一棵二叉树, 找到和为最小的子树, 返回其根节点。输入输出数据范围都在int内。
稍作修改即可!

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */
class ResultType {
public:
    int sum;
    ResultType():sum(0) {}
    ResultType(int _sum): sum(_sum) {}
};

class Solution {
public:
    /**
     * @param root: the root of binary tree
     * @return: the root of the minimum subtree
     */
    TreeNode * findSubtree(TreeNode * root) {
        helper(root);
        return node;
    }

    ResultType helper(TreeNode* root) {
        if (root == NULL) {
            return ResultType();
        }
        ResultType left = helper(root->left);
        ResultType right = helper(root->right);
        
        ResultType result = ResultType(left.sum + right.sum + root->val);
        if (node == NULL || result.sum < data.sum) {
            data = result;
            node = root;
        }

        return result;
    }

private:
    TreeNode* node = NULL;   //存储当前最优节点
    ResultType data;         //存储当前最优结果
};

给一棵二叉树,找出从根节点到叶子节点的所有路径。

输入:{1,2,3,#,5}
输出:[“1->2->5”,“1->3”]

可以用allpath记录所有路径。排名第一。。。但是再运行一次就倒数,;lintcode奇奇怪怪

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */

class Solution {
private:
    vector<string> allpath;   //用于记录所有路径并输出
    string mid;     //用于记录根节点
public:
    /**
     * @param root: the root of the binary tree
     * @return: all root-to-leaf paths
     */
    string getroot(TreeNode* root){
        return to_string(root->val);
    }
    
    void dfs(TreeNode* root,vector<string> path){
        if(!root->left && !root->right){
            allpath.push_back(accumulate(path.begin(), path.end(),mid));
            return;
        }
        if(root->left){
            // 输入左子树内容并记录
            path.push_back("->");
            path.push_back(getroot(root->left));
            dfs(root->left,path);
            path.pop_back();path.pop_back();
        }
        if(root->right){
            path.push_back("->");
            path.push_back(getroot(root->right));
            dfs(root->right,path);
            path.pop_back();path.pop_back();
        }
    }
    
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> path;
        if(root == NULL)  return path;
        mid = to_string(root->val);
        dfs(root,path);
        return allpath;
    }
};

最近公共祖先
思路:分治的方式,对于中间节点有以下几种情况:
1、左子树或者右子树,其中一个有返回值,则返回有的那个节点值(保证另一个可能是它子节点)
2、都没有,返回NULL
3、都有,返回该节点

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */


class Solution {
public:
    /*
     * @param root: The root of the binary search tree.
     * @param A: A TreeNode in a Binary.
     * @param B: A TreeNode in a Binary.
     * @return: Return the least common ancestor(LCA) of the two nodes.
     */
    TreeNode * lowestCommonAncestor(TreeNode * root, TreeNode * A, TreeNode * B) {
        if (!root || root == A || root == B) {
            return root;
        }
        TreeNode *left = lowestCommonAncestor(root->left, A, B);
        TreeNode *right = lowestCommonAncestor(root->right, A, B);
        if (left && right) {
            return root;
        }
        return left ? left : right;
    }
};

2、结构变化
翻转一棵二叉树。左右子树交换。

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */
class Solution {
public:
    /**
     * @param root: a TreeNode, the root of the binary tree
     * @return: nothing
     */
    void invertBinaryTree(TreeNode *root) {
        TreeNode *temp = root->left;
        root->left = root->right;
        root->right = temp;
        if (root->left!=NULL) invertBinaryTree(root->left);
        if (root->right!=NULL) invertBinaryTree(root->right);
    }
};

将一棵二叉树按照前序遍历拆解成为一个 假链表。所谓的假链表是说,用二叉树的 right 指针,来表示链表中的 next 指针。
思路:标准in place 解法

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    void flatten(TreeNode* root) {
        while (root != nullptr) {
            if (root->left != nullptr) {
                auto most_right = root->left; // 如果左子树不为空, 那么就先找到左子树的最右节点
                while (most_right->right != nullptr) most_right = most_right->right; // 找最右节点
                most_right->right = root->right; // 然后将跟的右孩子放到最右节点的右子树上
                root->right = root->left; // 这时候跟的右孩子可以释放, 因此我令左孩子放到右孩子上
                root->left = nullptr; // 将左孩子置为空
            }
            root = root->right; // 继续下一个节点
        }
        return;
    }
};

作者:hellozhaozheng
链接:https://leetcode-cn.com/problems/flatten-binary-tree-to-linked-list/solution/biao-biao-zhun-zhun-de-hou-xu-bian-li-dai-ma-jian-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

3、验证二叉查找树
给定一个二叉树,判断它是否是合法的二叉查找树(BST)
一棵BST定义为:

  • 节点的左子树中的值要严格小于该节点的值。
  • 节点的右子树中的值要严格大于该节点的值。
  • 左右子树也必须是二叉查找树。
  • 一个节点的树也是二叉查找树。
    Example
    样例 1:
    输入:{-1}
    输出:true
    解释:
    二叉树如下(仅有一个节点):
    -1
    这是二叉查找树。
    样例 2:
    输入:{2,1,4,#,#,3,5}
    输出:true
/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param root: The root of binary tree.
     * @return: True if the binary tree is BST, or false
     */
    bool isValidBST(TreeNode * root) {
        return dfs4(root);
    }
    
    bool dfs4(TreeNode * root) {
        if (root == NULL) {
            return true;
        }
        
        // Judge the left tree.
        if (!dfs4(root->left)) {
            return false;
        }
        
        // judge the sequence.
        // 这里,遍历方法的每一次赋值的root都是从最低到高的,第一次赋值就是最左的子叶,所以每次递归只需要判断一次就可以
        if (pre != NULL && root->val <= pre->val) {
            return false;
        }
        pre = root;
        
        // Judge the right tree.
        if (!dfs4(root->right)) {
            return false;
        }
        
        return true;
    }

private:
    TreeNode* pre = NULL;
};

给一棵二叉搜索树,写一个 KthSmallest 函数来找到其中第 K 小的元素。
思路:如果k为0,返回x即可。如果–k为0,返回当前节点值,否则继续向右子树搜索(右子树的节点值小于当前节点的父亲节点)。
注意这里要用中间变量x,保证k多自减一次!k是这里的局部变量,思路有点绕。

class Solution {
public:
    /**
     * @param root: the given BST
     * @param k: the given k
     * @return: the kth smallest element in BST
     */
    int kthSmallest(TreeNode * root, int k) {
        // write your code here
        return find(root, k);
    }
    int find(TreeNode* root, int& k) {
        if (root) {
            int x = find(root->left, k);
            return !k ? x : !--k ? root->val : find(root->right, k);  //如果k为0,返回x即可。如果--k为0,返回当前节点值,否则继续向右子树搜索。
        }
    }    
};

二叉查找树迭代器
经典题背诵!
leetcode上的解答更好一些。
初始化的时候先把root的所有左边的节点入栈
hasNext只要栈不空就是还有下一个元素
next,取出栈顶元素p(当前返回值)。把p的右子树的左节点全部入栈

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class BSTIterator {
private:
    stack<TreeNode*> stk;
public:
    BSTIterator(TreeNode* root) {
        TreeNode *p = root;
        while (p) {
            stk.push(p);
            p = p->left;
        }
    }
    
    /** @return the next smallest number */
    int next() {
        TreeNode *p = stk.top(); stk.pop();
        int res = p->val;
        p = p->right;
        while (p) {
            stk.push(p);
            p = p->left;
        }
        return res;
    }
    
    /** @return whether we have a next smallest number */
    bool hasNext() {
        return !stk.empty();
    }
};

/**
 * Your BSTIterator object will be instantiated and called as such:
 * BSTIterator* obj = new BSTIterator(root);
 * int param_1 = obj->next();
 * bool param_2 = obj->hasNext();
 */

给一棵非空二叉搜索树以及一个target值,找到在BST中最接近给定值的节点值。

中序遍历更新,时间复杂度O(n)。
其实找到相邻的大和小两个数,比一下就好了,时间复杂度O(logn)。

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param root: the given BST
     * @param target: the given target
     * @return: the value in the BST that is closest to the target
     */
    int closestValue(TreeNode * root, double target) {
        // write your code here
        int closest = root->val;
        while (root) {
            if (abs(closest - target) >= abs(root->val - target)) {
                closest = root->val;
            }
            root = target < root->val ? root->left : root->right;
        }
        return closest;        
    }
};

closest binary search tree value
给定一棵非空二叉搜索树以及一个target值,找到 BST 中最接近给定值的 k 个数。
报错!需要再修改!

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param root: the given BST
     * @param target: the given target
     * @param k: the given k
     * @return: k values in the BST that are closest to the target
     */
    stack<TreeNode* > findtarget(TreeNode * root,double target){
        stack<TreeNode* > bfvector;
        while(root){
            bfvector.push(root);
            if (root->val > target){
                root = root->left;
            }
            else{
                root = root ->right;
            }
        }
        return bfvector;
    }
    
    void bef(stack<TreeNode*> stack){
        TreeNode* node=stack.top();
        //右子树最左子叶
        if(node->left == NULL){
            node = stack.top(); stack.pop();
            while(stack.size()&&stack.top()->left==node){
                node = stack.top(); stack.pop();
            }
            return;
        }
        //左子树最右子叶
        else{
            node = node->left;
            while(node){
                stack.push(node);
                node = node->right;
            }
        }
        return;
    }

    void aft(stack<TreeNode*> stack){
        TreeNode* node = stack.top();
        if(node->right == NULL){
            node = stack.top(); stack.pop();
            while(stack.size()&&stack.top()->right==node){
                node = stack.top(); stack.pop();
            }
            return;
        }
        else{
            node = node->right;
            while(node){
                stack.push(node);
                node = node->left;
            }
        }
        return;
    }
    
    
    vector<int> closestKValues(TreeNode * root, double target, int k) {
        vector<int> output;
        if(!root||k==0) return output;
        stack<TreeNode*> bfvector = findtarget(root,target);
        stack<TreeNode*> afvector = findtarget(root,target);
        if(target < bfvector.top()->val){
            bef(bfvector); 
        }else{
            aft(afvector);
        }
        
        //找到最接近的root
        for(int i = 0;i<k;i++){
            if(bfvector.size()==0||afvector.size()!=0 && (target - bfvector.top()->val) > (afvector.top()->val-target)){
                output.push_back(afvector.top()->val);
                aft(afvector);
            }else{
                output.push_back(bfvector.top()->val);
                bef(bfvector);
            }
        }
        return output;
    }
};


在这里插入图片描述
补充学习二叉查找树的增删查改!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值