栈 队列 树的总结

因为这三个部分的题目可能分的类型比较少 也可能是我自己写的题目不够多 总结的可能不是很到位但我看了大部分中等题目基本都是多数基础题的结合 相对于栈 队列 树的知识点更多也更复杂 但是对于实际应用当中 参考了很多文章和题目 三者使用的并不是很多 我个人认为简单了解 当然有补充的欢迎提点 希望更加完善内容 感谢

用栈实现队列

leetcode 232

对于此题 仔细分析栈和队列的性质 先进后出 先进先出

而要用栈模拟出队列显然就需要两个栈 我们令其两个栈为instack outstack

举例为123 压入instack 123 依次出栈再压入outstack 321 在出栈为 123 就成为了队列

有了其思路 我们用stl更为简单的可以解题 

    stack<int> instack, outstack;
    void in2out(){
        while(!instack.empty()){
            outstack.push(instack.top());
            instack.pop();
        }
    }
    MyQueue() {  }
    
    void push(int x) {
        instack.push(x);
    }
    
    int pop() {
        if(outstack.empty()){
            in2out();
        }
        int x = outstack.top();
        outstack.pop();
        return x;
    }
    
    int peek() {
        if(outstack.empty()){
            in2out();
        }
        return outstack.top();
    }
    
    bool empty() {
        return instack.empty() && outstack.empty();
    }

  字符串解码

leetcode 394

对于此题我们观察样例  对于1  3  4  很显然 都可以通过简单的模拟 但对于样例三我们应当想到用递归的方式解题  无非是对数字 字符串  前后中括号 进行判断和相对应的不同处理

我们就对示例三进行分析

显然是先进后出 用栈进行处理   

先将其分为独立元素   对其依次压栈  当遇到右中括号时  进行出栈   

当遇到第一个左中括号   访问前面的数字  对其处理 再压入 栈 即可

再读取原来的字符串  进行以上操作

注意  对于访问左中括号前面的数字 我们很可能不是一位数    所以对其要有相应的处理方式

对于此种方式的题解可以自行处理一下   我们对于此解优化  不妨将数字和字符分边分为两个栈

如果当前的字符为数字,解析出一个数字并进栈(可能为多位数
如果当前的字符为字母或者左括号,直接进栈
如果当前的字符为右括号,开始出栈,一直到左括号出栈,出栈序列反转后拼接成一个字符串,此时取出栈顶的数字,就是这个字符串应该出现的次数,我们根据这个次数和字符串构造出新的字符串并进栈

class Solution {
public:
    string getDigits(string &s, size_t &ptr) {
        string ret = "";
        while (isdigit(s[ptr])) {
            ret.push_back(s[ptr++]);
        }
        return ret;
    }

    string getString(vector <string> &v) {
        string ret;
        for (const auto &s: v) {
            ret += s;
        }
        return ret;
    }

    string decodeString(string s) {
        vector <string> stk;
        size_t ptr = 0;

        while (ptr < s.size()) {
            char cur = s[ptr];
            if (isdigit(cur)) {
                string digits = getDigits(s, ptr);
                stk.push_back(digits);
            } else if (isalpha(cur) || cur == '[') {
                stk.push_back(string(1, s[ptr++])); 
            } else {
                ++ptr;
                vector <string> sub;
                while (stk.back() != "[") {
                    sub.push_back(stk.back());
                    stk.pop_back();
                }
                reverse(sub.begin(), sub.end());
                stk.pop_back();
                int repTime = stoi(stk.back()); 
                stk.pop_back();
                string t, o = getString(sub);
                while (repTime--) t += o;
                stk.push_back(t);
            }
        }

        return getString(stk);
    }
};

这里用两个循环处理更为方便理解  但对于本题还有很多方式进行处理 

若是不考虑其复杂度 甚至可以暴力模拟的方式访问  但是我们这里不在赘述 主要体现栈的优势

二叉树的三种遍历方式

leetcode   94 144 145

这里的三种遍历方式总结更加体现出递归的思想  其解法都是有相同之处  这里直接给出题解  也不难理解 这里就不赘述  

vector<int> inorderTraversal(TreeNode* root){
            stack<TreeNode*> p;
            vector<int> res;
            auto m= root;
            while(root != nullptr ){
                p.push(m);
            }
                while(root != nullptr){
                    p.push(root->val);
                    root = root->left;
                }
                p.pop();
                res.push_back(root->val);
                root = root->right;
            }
            return res;
        }
void preordernode(TreeNode* root,vector<int>& res){
        if(root == nullptr) return;
        res.push_back(root->val);
        preordernode(root->left,res);
        preordernode(root->right,res);
        
    }
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> res;
        preordernode(root,res);
    return res;
    }

对于上述而言 对于第一个中序遍历 我给出的不是递归但可以用递归实现 相反后两者的前序和后序也可以通过循环实现

对称二叉树

leetcode101 

 此题也不难理解  无非也时递归的方式  依次判断

左子树的左孩子,右子树的右孩子  和  左子树的右孩子,左子树的右孩子

是否相同即可

 // bool deepcheck(TreeNode* left,TreeNode* right){
    //     if(left == nullptr&&right == nullptr) return true;
    //     if(left == nullptr||right == nullptr) return false;
    //     if(left->val != right->val) return false;
    //     return deepcheck(left->left,right->right)&&deepcheck(left->right,right->left);
    // }
    // bool isSymmetric(TreeNode* root) {
    //     if(root == nullptr) return true;
    //     return deepcheck(root->left,root->right);
    // }

当我们用循环迭代思考时   队列实现

依次将根节点的左右子树入队 

对其出队并判断并将其左右子树入队(放

的顺序为 左子树的左孩子 右子树的右孩子 左子树的右孩子 右子树的左孩子)

在进行重新出队入队 依次遍历树

可以尝试自行实现一下

二叉树的最大深度 平衡二叉树

leetcode 104 110

递归的调用左子树和右子树的高度取最大值加1

int maxDepth(TreeNode* root) {
        if(root == nullptr) return 0;
        else return max(maxDepth(root->right),maxDepth(root->left))+1;
    }

同样的也可以使用队列实现  

基本思想就是统计每一层 综合对其处理

显然只需要和上面的方式类似  多记录一下就可以实现

    int helper(TreeNode* root){
        if(root == nullptr) return 0;
        int left = helper(root->left);
        int right = helper(root->right);
        if(left == -1 ||right == -1 || abs(left-right) > 1) return -1;
        return max(left,right) +1;
    }
    bool isBalanced(TreeNode* root) {
        if(root == nullptr) return true;
        return helper(root) != -1;
    }

 翻转二叉树

    TreeNode* invertTree(TreeNode* root) {
        if(root == nullptr) return nullptr;
        invertTree(root->right);
        invertTree(root->left);
        TreeNode* temp = root->right;
        root->right = root->left;
        root->left = temp;
        return root;
    }

 其实对于树的总结相当于是对数据结构的复习 想到总结这篇文章的原因也是在巩固数据结构的基础上而产生的  对于栈队列树  这三种特殊的存储方式  再多的技巧确实也没有  对于栈和队列  往往都有相似的处理方式 和思考模式   而对于树而言 更多的是 递归和循环 基于以上思考  

总结

由此 虽然也就两篇文章草草概括了数据结构的内容 但也可以看出数据结构是算法中非常渺小的一部分  但却至关重要 所以我认为对此更需要夯实内容

当然对于树而言  有许多细小的知识点并没有提到 原因也是太杂 不好细分统计  也就举了几个常见的且十分重要的进行总结

倘若读者有更好的总结 也可以帮助我更加完善其内容 也欢迎对我草草几笔总结的文章斧正

感谢

cs202  zhoujie

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值