Leetcode刷题笔记(C++)—— 栈队列

Leetcode刷题笔记(C++)—— 栈队列

整理一下刷题过程中的思路,在这里进行一下总结与分享。
github地址:https://github.com/lvjian0706/Leetcode-solutions
github项目是刚刚新建的,陆续会将整理的代码以及思路上传上去,代码是基于C++与python的。同时会将基础的排序算法等也一并进行整理上传。

94. 二叉树的中序遍历

给定一个二叉树,返回它的中序 遍历。

示例:

输入: [1,null,2,3]
1

2
/
3

输出: [1,3,2]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?

/**
 * 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 DFS(TreeNode* root, vector<int> &ans){
    
    
        if(!root) return;
        DFS(root->left, ans);
        ans.push_back(root->val);
        DFS(root->right, ans);
    }

    /*
    中序遍历,可以使用回溯思想
    */
    vector<int> inorderTraversal(TreeNode* root) {
    
    
        vector<int> ans;
        DFS(root, ans);
        return ans;
    }
};


/**
 * 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:
    /*
    迭代方法:(使用vector和stack共同解决)
    1. 中序遍历,访问左孩子节点存到栈中;
    2. 访问结束后,pop()出栈顶元素,存到结果数组中;
    3. 将root定义为栈顶元素的右孩子,遍历右子树;
    */
    vector<int> inorderTraversal(TreeNode* root) {
    
    
        vector<int> ans;
        stack<TreeNode*> inorder_tree;
        while(root || !inorder_tree.empty()){
    
    
            while(root){
    
    
                inorder_tree.push(root);
                root = root->left;
            }
            TreeNode* temp = inorder_tree.top();
            inorder_tree.pop();
            ans.push_back(temp->val);
            root = temp->right;
        }
        return ans;
    }
};

150. 逆波兰表达式求值

根据 逆波兰表示法,求表达式的值。

有效的运算符包括 +, -, *, / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

说明:

整数除法只保留整数部分。
给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。

示例 1:
输入: [“2”, “1”, “+”, “3”, “"]
输出: 9
解释: 该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
示例 2:
输入: [“4”, “13”, “5”, “/”, “+”]
输出: 6
解释: 该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
示例 3:
输入: [“10”, “6”, “9”, “3”, “+”, “-11”, "
”, “/”, “*”, “17”, “+”, “5”, “+”]
输出: 22
解释:
该算式转化为常见的中缀算术表达式为:
((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22

逆波兰表达式:
逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。
平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:
去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中。

class Solution {
    
    
public:
    /*
    逆波兰表达式求值:
    使用栈来存储每个数字以及当前的计算结果;为了方便定义flag标志位,使用switch语句进行判断;
    1. 当字符串长度大于1或字符串的第一个元素大于‘0’小于‘9’时,说明字符串中为数字,将string转为int后入栈;(注意处理2位数以上的数以及负数)
    2. 当字符串中存储的是运算符:将栈顶的两个元素取出后进行计算,结果重新入栈;
    3. 栈顶元素为最终结果;
    */
    int evalRPN(vector<string>& tokens) {
    
    
        stack<int> nums;
        static const int NUMBER = 1;
        static const int OPERATOR = 2;
        int flag = NUMBER;
        for(int i=0; i<tokens.size(); i++){
    
    
            string mem = tokens[i];
            if(mem.size()>1 || (mem[0]>='0' && mem[0]<='9')) flag = NUMBER;
            else flag = OPERATOR;
            switch(flag){
    
    
                case NUMBER:{
    
    
                    int j=0, temp=0;
                    if(mem[0]=='-') j++;
                    while(mem[j]>='0' && mem[j]<='9'){
    
    
                        temp = temp * 10 + mem[j] - '0';
                        j++;
                    }
                    if(mem[0]=='-') nums.push(0-temp);
                    else nums.push(temp);
                    break;
                }
                case OPERATOR:{
    
    
                    int num1 = nums.top();
                    nums.pop();
                    int num2 = nums.top();
                    nums.pop();
                    if(mem[0]=='+') nums.push(num2+num1);
                    else if(mem[0]=='-') nums.push(num2-num1);
                    else if(mem[0]=='*') nums.push(num2*num1);
                    else if(mem[0]=='/') nums.push(num2/num1);
                    break;
                }
            }
        }
        return nums.top();
    }
};

155. 最小栈

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。

示例:
输入:
[“MinStack”,“push”,“push”,“push”,“getMin”,“pop”,“top”,“getMin”]
[[],[-2],[0],[-3],[],[],[],[]]
输出:
[null,null,null,null,-3,null,0,-2]
解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
提示:
pop、top 和 getMin 操作总是在 非空栈 上调用。

class MinStack {
    
    
public:
    /*
    设计常数时间内检索到最小元素的栈:
    需要定义变量存储最小值,考虑到当最小值弹出后能及时更新最小值,定义了min_stack存储截止到每个位置的最小值;
    1. push(),top()操作正常;
    2. getMin()操作直接返回min_stack的栈顶元素;
    3. push()操作:
    3.1 real_stack直接入栈;
    3.2 判断x与min_stack的栈顶元素谁小,将最小值入栈;
    */

    /** initialize your data structure here. */
    MinStack() {
    
    

    }
    
    void push(int x) {
    
    
        real_stack.push(x);
        if(min_stack.empty()) min_stack.push(x);
        else min_stack.push(min(x, min_stack.top()));
    }
    
    void pop() {
    
    
        real_stack.pop();
        min_stack.pop();
    }
    
    int top() {
    
    
        return real_stack.top();
    }
    
    int getMin() {
    
    
        return min_stack.top();
    }
private:
        stack<int> real_stack;
        stack<int> min_stack;
};

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack* obj = new MinStack();
 * obj->push(x);
 * obj->pop();
 * int param_3 = obj->top();
 * int param_4 = obj->getMin();
 */

394. 字符串解码

给定一个经过编码的字符串,返回它解码后的字符串。

编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。

你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。

此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。

示例 1:
输入:s = “3[a]2[bc]”
输出:“aaabcbc”
示例 2:
输入:s = “3[a2[c]]”
输出:“accaccacc”
示例 3:
输入:s = “2[abc]3[cd]ef”
输出:“abcabccdcdcdef”
示例 4:
输入:s = “abc3[cd]xyz”
输出:“abccdcdcdxyz”

class Solution {
    
    
public:

    /*
    将字符串s重复n遍返回;
    */
    string repeatStr(string s, int n){
    
    
        string ans = "";
        for(int i=0; i<n; i++){
    
    
            ans.append(s);
        }
        return ans;
    }

    /*
    给定一个经过编码的字符串(编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。),返回它解码后的字符串:
    1. 使用栈来进行计算,建立两个栈分别存储k和encoded_string;
    2. 定义三个状态:BEGIN,NUMBER,CHARATOR分别代表起始状态,处理数字k,处理encoded_string;
    3. 遍历s,进行处理:
    3.1 BEGIN:判断第一个字符为数字还是encoded_string;
    3.2 NUMBER:将数字入nums栈;
    3.3 CHARATOR:
    3.3.1 s[i]!=']'时,将字符直接入dec_str栈;
    3.3.2 s[i]==']'时,解码字符串:
    3.3.2.1 取出字符串栈中的元素,直到取到'['为止,取出的元素则为需要重复的元素;
    3.3.2.2 将取出的字符连成字符串并重复n遍,n为nums栈中的栈顶元素;
    3.3.2.3 将新字符串入dec_str栈;
    4. dec_str中最后存储着解码后的字符串片段,拼接之后就是最终答案;
    */
    string decodeString(string s) {
    
    
        stack<int> nums;
        stack<string> dec_str;
        static const int BEGIN = 0;
        static const int NUMBER = 1;
        static const int CHARATOR = 2;
        int flag = BEGIN;
        for(int i=0; i<s.size(); i++){
    
    
            switch(flag){
    
    
                case BEGIN:{
    
    
                    if(s[i]>='0' && s[i]<='9') flag = NUMBER;
                    else flag = CHARATOR;
                    i--;
                    break;
                }
                case NUMBER:{
    
    
                    if(s[i]<'0' || s[i]>'9') flag = CHARATOR;
                    else{
    
    
                        int temp = 0;
                        while(s[i]>='0' && s[i]<='9'){
    
    
                            temp = temp * 10 + s[i] - '0';
                            i++;
                        }
                        nums.push(temp);
                    }
                    i--;
                    break;
                }
                case CHARATOR:{
    
    
                    if(s[i]>='0' && s[i]<='9'){
    
    
                        flag = NUMBER;
                        i--;
                    } 
                    else if(s[i]!=']'){
    
    
                        string mem;
                        mem.push_back(s[i]);
                        dec_str.push(mem);
                    }
                    else{
    
    
                        /*
                        1. 取出字符串栈中的元素,直到取到'['为止,取出的元素则为需要重复的元素;
                        2. 将取出的字符连成字符串并重复n遍,n为nums栈中的栈顶元素;
                        3. 将新字符串入dec_str栈;
                        */
                        string temp_str = "";
                        while(dec_str.top()[0]!='['){
    
    
                            string top_string = dec_str.top();
                            dec_str.pop();
                            temp_str.insert(0, top_string);
                        }
                        dec_str.pop(); //去掉'['
                        int times = nums.top();
                        nums.pop();
                        string repeat_str = repeatStr(temp_str, times);
                        dec_str.push(repeat_str);
                    }
                    break;
                }
            }
        }
        string ans = "";
        while(!dec_str.empty()){
    
    
            string mem_str = dec_str.top();
            dec_str.pop();
            ans.insert(0, mem_str);
        }
        return ans;
    }
};

猜你喜欢

转载自blog.csdn.net/weixin_43273742/article/details/107741524
今日推荐