力扣刷题笔记:栈和队列(13)

20. 有效的括号(栈+哈希表)

1、用栈存并且匹配括号
2、用map存三种括号匹配情况
3、直接返回栈是否为空即可

class Solution {
public:
    bool isValid(string s) {
    map<char,char> res={
        {'(',')'},{'[',']'},{'{','}'}
    };
    stack<char> stk;
    for(int i=0;i<s.size();i++){
        if(s[i]=='('||s[i]=='{'||s[i]=='[') stk.push(s[i]);
        else if(stk.empty())  return false;
        else if(res[stk.top()]==s[i]) stk.pop();
        else return false;
    }
    return stk.empty();
    }
};

32. 最长有效括号(栈存下标)

栈中只保存左括号的下标,每遍历到右括号就出栈,比较当前最大合法长度

class Solution {
public:
    int longestValidParentheses(string s) {
        int maxans = 0;
        stack<int> stk;
        stk.push(-1);
        for (int i = 0; i < s.length(); i++) {
            if (s[i] == '(') 
                stk.push(i);
            else {
                stk.pop();
                if (stk.empty()) 
                    stk.push(i);
                else 
                    maxans = max(maxans, i - stk.top());
            }
        }
        return maxans;
    }
};

155. 最小栈(双栈-辅助栈)

1、用一个辅助栈存新数和栈底数之中的最小值,辅助栈大小和原栈大小一致,节省判断
2、先对栈进行判空,再取top值,否则报错
3、原栈压入可以单独提前,不用进行判断,注意不漏掉等于的情况

class MinStack {
public:
    /** initialize your data structure here. */
    stack<int> res,help;
    MinStack() {
    }
    void push(int x) {
    //缺少等于号的判断,导致提交一直溢出,可以把res.push提到前面
    res.push(x);
	//判空必须放前面,如果help为空则不判断第二个
    if(help.empty()||x<=help.top())
        help.push(x);
    else if(!help.empty()&&x>help.top()){
        int temp=help.top();
        help.push(temp);
    }}
    void pop() {
    if(!res.empty()&&!help.empty()){
        res.pop();
        help.pop();}
    }
    int top() {
    return res.top();
    }
    int min() {
    return help.top();
    }
};

224. 基本计算器(栈)

用一个栈记录正负号

class Solution {
public:
    int calculate(string s) {
        stack<int> ops;
        ops.push(1);
        int sign = 1,ret = 0,n = s.length(),i = 0;
        while (i < n) {
            if (s[i] == ' ') {
                i++;
            } else if (s[i] == '+') {
                sign = ops.top();
                i++;
            } else if (s[i] == '-') {
                sign = -ops.top();
                i++;
            } else if (s[i] == '(') {
                ops.push(sign);
                i++;
            } else if (s[i] == ')') {
                ops.pop();
                i++;
            } else {
                long num = 0;
                while (i < n && s[i] >= '0' && s[i] <= '9') {
                    num = num * 10 + s[i] - '0';
                    i++;
                }
                ret += sign * num;
            }
        }
        return ret;
    }
};

227. 基本计算器 II(栈)

维持一个数字栈,不存标点符号,碰到加减号往里面塞正负数,碰到乘除号进行计算,最后累加栈中的数

class Solution {
public:
    int calculate(string s) {
        vector<int> stk;
        char preSign = '+';
        int num = 0;
        int n = s.length();
        for (int i = 0; i < n; ++i) {
            if (isdigit(s[i])) 
                num = num * 10 + int(s[i] - '0');
            if (!isdigit(s[i]) && s[i] != ' ' || i == n - 1) {
                switch (preSign) {
                    case '+':
                        stk.push_back(num);
                        break;
                    case '-':
                        stk.push_back(-num);
                        break;
                    case '*':
                        stk.back() *= num;
                        break;
                    default:
                        stk.back() /= num;
                }
                preSign = s[i];
                num = 0;
            }
        }
        return accumulate(stk.begin(), stk.end(), 0);
    }
};

225. 用队列实现栈(单队列)

1、有两种方法,单队列和双队列,单队列比较好理解
2、主要是入栈操作,每次入栈先入单队列,然后把之前所有元素弹出再重新入队,保证队头是刚入的栈顶数据

class MyStack {
public:
    queue<int> q;
    /** Initialize your data structure here. */
    MyStack() {
    }
    /** Push element x onto stack. */
    void push(int x) {
        int n = q.size();
        q.push(x);
        for (int i = 0; i < n; i++) {
            q.push(q.front());
            q.pop();
        }
    }
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        int r = q.front();
        q.pop();
        return r;
    }
    /** Get the top element. */
    int top() {
        int r = q.front();
        return r;
    }
    /** Returns whether the stack is empty. */
    bool empty() {
        return q.empty();
    }
};

232. 用栈实现队列(双栈)

用两个栈in和out,in只负责进,把in全部塞进out抽出成为一个公共函数,弹出和栈顶都从out拿,如果out是空的,就调用该函数,把in中的值全部挪到out中

class MyQueue {
private:
    stack<int> inStack, outStack;
    void in2out() {
        while (!inStack.empty()) {
            outStack.push(inStack.top());
            inStack.pop();
        }
    }
public:
    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();
    }
};

239. 滑动窗口最大值(优先队列)

优先队列是最大堆,栈顶保存最大的元素,优先队列设置为数和位置的元组,每一次窗口都弹出最大值保存,优先队列用一个while弹出不在窗口的最大值

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        int n = nums.size();
        priority_queue<pair<int, int>> q;
        for (int i = 0; i < k; ++i) 
            q.emplace(nums[i], i);
        vector<int> ans = {q.top().first};
        for (int i = k; i < n; ++i) {
            q.emplace(nums[i], i);
            while (q.top().second <= i - k) 
                q.pop();
            ans.push_back(q.top().first);
        }
        return ans;
    }
};

394. 字符串解码

1、用一个string栈(用char栈会有逆序问题)和数字栈存字符串,对数字、字符、左右括号四种情况进行判断。
2、由于数字可能是两位数,所以数字不能直接入数字栈,用int型进位进行存储。
3、由于字符串取出时会存在逆序问题,所以不能挨个字符入栈,先暂时存入中间字符串。
4、结果字符串和中间字符串共用一个字符串即可。

class Solution {
public:
    string decodeString(string s) {
    stack<int> stkint;//数字栈
    stack<string> stkstring;//用字符串栈代替字符栈,保证不会逆序
    string tempstr="";//中间字符串和结果字符串共用一个
    int num=0;
    for(int i=0;i<s.size();i++){
        if(isdigit(s[i])) 
            num=num*10+s[i]-'0';//不能直接入栈,因为有两位数,用int进位比字符串更方便
        else if(isalpha(s[i]))
            tempstr+=s[i];//暂时用字符串存,不要入字符栈,保证不会逆序
        else if(s[i]=='['){ 
            stkint.push(num);
            num=0;
            stkstring.push(tempstr);
            tempstr="";
        }
        else if(s[i]==']'){
            int count=stkint.top();
            stkint.pop();
            for(int j=0;j<count;j++)
                stkstring.top()+=tempstr;//重复多次同时又能保证顺序
            tempstr=stkstring.top();
            stkstring.pop();
        } 
    }
    return tempstr;
    }
};

739. 每日温度

1、用单调栈,来保存当前单调递减的温度序列。
2、栈内存温度序号值,不用存温度值,温度在数组T内,天数差=序号差num-temp
3、循环内不用while入栈

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& T) {

    stack<int> stk;
    vector<int> ans(T.size());
    int num=0;
    
    while(num<T.size()){
        //不用入温度,入序列号
        while(!stk.empty()&&T[num]>T[stk.top()]) {
            int temp=stk.top();
            stk.pop();
            ans[temp]=num-temp;
        }
        //不用while入栈
        stk.push(num++);
    }

    return ans;
    }
};

剑指 Offer 09. 用两个栈实现队列

1、用辅助栈实现,插入操作与压栈操作相同,弹出操作先将所有元素放入辅助栈,再弹出栈底元素,最后放入原栈
2、栈的操作用empty判空,不能用变量等于pop值。

class CQueue {
public:
    stack<int> stk,stk1;
    CQueue() {
    }
    void appendTail(int value) {
        stk.push(value);
    }
    int deleteHead() {
        if(stk.empty()) return -1;
        //不能写stk.top!=NULL 要用empty进行判空,否则会报错
        while(!stk.empty()) {
            //不能直接用n等于栈的pop
            int n=stk.top();
            stk.pop();
            stk1.push(n);
        }
        int ans=stk1.top();
        stk1.pop();
        while(!stk1.empty()) {
            int n=stk1.top();
            stk1.pop();
            stk.push(n);
        }
        return ans;
    }
};

剑指 Offer 59 - II. 队列的最大值

1、队列题要用辅助队列,不能用辅助栈
2、用辅助队列存当前队列的最大值
3、压入元素时,先弹出辅助栈中所有小于当前值的元素
4、弹出队首元素时,判断该元素是否在辅助队列里,如果在,则同时弹出辅助队列队首元素

class MaxQueue {
public:
    queue<int> q;
    deque<int> help;
    MaxQueue() {
    }
    int max_value() {
        if(help.empty()) return -1;
        return help.front();
    }
    void push_back(int value) {
        //empty判断必须放前面,防止溢出
        while(!help.empty()&&help.back()<value) help.pop_back();
        q.push(value);
        help.push_back(value);
    }
    int pop_front() {
        if(q.empty()) return -1;
        int a=q.front();
        if(a==help.front()) help.pop_front();
        q.pop();
        return a;
    }
};

剑指 Offer 59 - I. 滑动窗口的最大值

1、用单调的双端队列存当前滑动窗口中的最大值的序号,而不是最大值本身
2、由于窗口的大小已经固定,不能用双指针法
3、每次弹出队尾小于当前值的元素
4、每次弹出队首不在当前滑动窗口序号范围内的元素
5、弹入当前值并且输出当前窗口最大值

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
    //单调的双端队列
    deque<int> temp;
    vector<int> ans;
    //i是数组nums的索引
    for(int i=0;i<nums.size();i++)
    {
        //将当前滑动窗口的最大数置于双端队列队首,比较的是nums大小
        while(!temp.empty()&&nums[i]>nums[temp.back()]) temp.pop_back();
        //保证当前双端队列队首最大值是在滑动窗口内
        while(!temp.empty()&&temp.front()<i-k+1) temp.pop_front();
        //放入当前值
        temp.push_back(i);
        //输出当前滑动窗口内的最大值
        if(i>=k-1) ans.push_back(nums[temp.front()]);
    }
    return ans;
    }
};

你可能感兴趣的:(力扣刷题,leetcode,算法,数据结构)