C++算法学习(栈)

什么是栈?

是一个运算受限制的线性表,只能在表尾进行插入和删除,也就是先进后出,后进先出。(新手建议搜一本算法图解,讲的很明白)

题目类型

原理学习:155、71、682、341
单调栈:42、496、1081
辅助栈(只是用来计数的一个工具):1021、331
个人感觉没有新类型的,基本上就不重复记录题目了。

顺序栈

理解的话百度百科就可以,俺也是记笔记,怕误导你们。链接
顺序栈的适用情况(算法太多总结一下):
有明显的排序现象,或者是找左边啊右边啊第一个最大(最小)的情况。

实践题目

155. 最小栈

struct Node{
        int val;
        int min;
        Node *next;
};
//建立结构体,写入题目要求的功能
class MinStack {
private:
Node* head;
public:
    MinStack() { 
    head = nullptr;
    }
    //构造函数
    void push(int x) {
    if(head != NULL){
    int temp = (head -> min > x)? x : head -> min;
    Node *node = new Node();
    node -> min = temp;
    node -> val = x;
    node -> next = head;
    head = node;
    }//这里使用头插
    else{
        head = new Node();
        head -> val = x;
        head -> min = x;
        head -> next = nullptr;
    }
    }
    void pop() {
        head = head ->next;
    }
    
    int top() {
    return head -> val;
    }
    int getMin() {
    return head -> min;
    }
};

42. 接雨水

这个用单调递减栈:
稍微讲一下单调递减栈和单调递增栈:
(以单调递减栈为例)
1.若数据小于栈顶元素,则入栈。
2.如果数据比栈顶元素大,那么栈顶元素出栈,一直到数据比栈顶元素小为止。

打个比方:4312
4,3,1正常入栈
到2,和1比,1出栈,和3比,比3小,就出结果啦。

这道题我们只需要求有水滴的地方的面积,所以我们栈里存的数据是数组的下标(当然有其他解法,但是我这里用栈)

class Solution {
public:
    int trap(vector<int>& height) {
    stack<int> num;
    int sum = 0;
    for(int i = 0;i < height.size();i++){
        while(!num.empty() && height[num.top()] < height[i]){
            int val = height[num.top()];
            num.pop();
            if(num.empty()) break;
            int l = i - num.top() - 1;
            int h = min(height[i],height[num.top()]) - val;
            sum += l * h;
        }
        num.push(i);
    }
    return sum;
    }
};

71. 简化路径

读完题目和例子,我得到的信息:
1、如果栈顶是/下一个要入栈的数据也是/那么栈顶出栈,下一个数据正常入栈。
2、如果栈顶是/(不排除例子乱输入a…这种情况)下一个要入栈的数据是…则数据全部出栈,下一个数据入栈。
3、如果栈顶是/,下一个要入栈数据是.那么栈顶出栈,而且继续出栈到下一个栈顶为/
4、在程序运行最后,判断栈顶是否是/,如果是就出栈。
怎么说呢,我们只需要判断两个/之间的东西是什么,再做相应操作就好了。

class Solution {
public:
    string simplifyPath(string path) {
    path += '/';
    stack<string> stk;
    string str;
    for(char m : path){
        if(m == '/'){
            //如果str为.那么直接清除str即可
            //如果str为..那么stk把上一个数据给出栈(这里有特殊情况/../需要判断是否为空栈)
            //其他情况就把数据读进去,注意我这么写'/'这个字符是不会读进去的
            if(str == ".." && !stk.empty()){
                stk.pop();
            }
            else if(str != "." && !str.empty() && str != ".."){
                stk.push(str);
            }
            str.clear();
        }
        else{
            str.push_back(m);
        }
    }
    string result;
    if(stk.empty()) return "/";
    while(!stk.empty()){
        result = "/" + stk.top() + result;
        stk.pop();
    }
    return result;
    }
};

496. 下一个更大元素 I

这个题用递减数列,把小数据存进去找右边第一个大的数据,再把这个关系存进去(记得把栈顶出栈),我用hashmap进行关系建立,最后查结果,查不到就返回-1。

class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
    stack<int> num;
    vector<int> answer;
    map<int, int> s1;
    for(auto a:nums2){
        while(!num.empty() && num.top() < a){
            s1[num.top()] = a;
            num.pop();
        }
        num.push(a);
    }
    for(auto a:nums1){
        if(s1.count(a) == 0) answer.push_back(-1);
        else answer.push_back(s1[a]);
    }
    return answer;
    }
};

682. 棒球比赛

这个题也是给练手题,本来以为用asl码,但是俺也不知道棒球比赛能有60分?

class Solution {
public:
    int calPoints(vector<string>& ops) {
    stack<int> num;
    int sum = 0;
    for(auto a:ops){
        if(a[0] == '+'){
            int t = num.top();
            num.pop();
            int t1 = t + num.top();
            num.push(t);
            num.push(t1);
        }
        else if(a[0] == 'D'){
            int t = num.top() + num.top();
            num.push(t);
        }
        else if(a[0] == 'C'){
            num.pop();
        }
        else num.push(stoi(a));//大家可以记一下这个函数
    }
    while(!num.empty()){
        sum += num.top();
        num.pop();
    }
    return sum;
    }
};

1021. 删除最外层的括号

我开始是寻找两个栈空之间的距离,把这两个之间的东西加起来,但是看了一下大佬的写的= =自愧不如,参考的力扣用户:ping-ze-ping-ze-ping-ping-ze的代码。

class Solution {
public:
    string removeOuterParentheses(string S) {
        stack<char> a;
        string b("");
        for(int i = 0;i < S.length();i++){
            if(S[i] == ')') a.pop();
            if(!a.empty() ) b += S[i];
          if(S[i] == '(')  a.push(S[i]);
        }
        return b;
    }
}

341. 扁平化嵌套列表迭代器

难度中等题里面适合练手(俺开始没看懂题意,写的好烦啊)。

class NestedIterator {
private:
stack<int> a;
stack<int> b;
void add(vector<NestedInteger> nested){
    for(auto nestedi : nested)
        if(nestedi.isInteger()) a.push(nestedi.getInteger());
        else add(nestedi.getList());
}
public:
    NestedIterator(vector<NestedInteger> &nestedList) {
        add(nestedList);
        while(!a.empty()){
            b.push(a.top());
            a.pop();
        }
    }
    int next() {
        int ai = b.top();
        b.pop();
        return ai;
    }
    bool hasNext() {
        return !b.empty();
    }
};

331. 验证二叉树的前序序列化

这是一棵二叉树 = =反正我的印象就是:空节点数=非空节点数 + 1,建议几个关于树的定理可以记一下。
然后#就是空,数就是非空,#比数多1个,那么如果是数就进栈,如果是#就出栈,那么当字符是#的时候而且#是字符串最后一位看栈是否为空,若为空那么就是验证成功,非空就是验证失败。
然后俺写出来就遇见两位的数字19这种,然后这是个string,难搞= =借鉴了一下别人的做法,他每次找到数,就往下找到下一个”,“数有很多”,“只有一个啊不得不说这个想法真厉害。

class Solution {
private:
stack<char> a;
public:
    bool isValidSerialization(string preorder) {
    if (preorder.empty()) return false;
    for(int i = 0;i < preorder.length();i++){
        if(preorder[i] == '#'){
            if(a.empty()) return i == preorder.size() - 1;
            else {
                a.pop();
                i++;
            }
        }
        else{
            while (i < preorder.size() && preorder[i] != ',') i++;
            a.push(preorder[i]);
        }
    }
    return false;
    }
};

1081. 不同字符的最小子序列

这个问题原理很简单,就是一个单调栈(单调递增),如果栈内已经存在数据就吧这个数据给pass掉,如果数据比栈顶小,那么就删栈顶数据直到栈顶数据小于数据为止。因为C++的库函数实在感觉少,就用vector来代替,其实大家用go啊python啊可以直接调库。

class Solution {
public:
    bool get_num(int i,string s,char si){
        for(int j = i + 1;j<s.length();j++) if(s[j] == si) return true;
        return false;
    }
    string smallestSubsequence(string s) {
     string str("");
     vector<char> already;
     int i = -1;
     for(auto si :s){
         i++;
         if(count(already.begin(),already.end(),si) > 0) continue;
         while(!already.empty() && already.back() > si && get_num(i,s,already.back()) == true) already.pop_back();
         already.push_back(si);
     }
     while(!already.empty()){
         str = already.back() + str;
         already.pop_back();
     }
     return str;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值