栈、队列牛客网(C++)

题目1(有效括号序列)

在这里插入图片描述

收获

1:这到题和之前做过的判断表达式是否正确的题很相似,就是省略了考虑数字的情况相对来说更简单了些,一些注意事项自己也考虑了,比如栈空的时候遇到右括号,以及循环结束后栈内还有没处理的括号这两种特殊情况,自己在编写的时候还是比较容易的~

代码

class Solution {
public:
    /**
     * 
     * @param s string字符串 
     * @return bool布尔型
     */
    bool isValid(string s) {
        // write code here
        stack<char >res;
        char temp;
        for(int i=0;i<s.size();i++){
            if(s[i]=='('||s[i]=='['||s[i]=='{')
                res.push(s[i]);
            if(s[i]==')'&&(res.size()==0||res.top()!='('))
                return false;
            else if (s[i]==')'&&res.top()=='(')
                res.pop();
            else if(s[i]==']'&&(res.size()==0||res.top()!='['))
                return false;
            else if (s[i]==']'&&res.top()=='[')
                res.pop();
            else if(s[i]=='}'&&(res.size()==0||res.top()!='{'))
                return false;
            else if (s[i]=='}'&&res.top()=='{')
                res.pop();
        }
        if(res.size()!=0)
            return false;
        return true;
    }
};

题目2(表达式求值)

在这里插入图片描述

收获

1:这道题的难度还是比较大的,最开始源于记忆,想要维持两个栈,一个符号栈和一个数据栈,但是由于要考虑的一些符号之间的关系+和×以及(和×有丢丢复杂,还是放弃了,选择参考了参考答案
2:初始值对op=’+‘,刚开始一直不理解,万一第一个运算符号是-呢,后来才发现第一个操作符起到的作用只是将第一个值入栈而已,并没有直接运算,后面要运算的地方将s[i]赋值给了op,然后在中间遇到(直接进入递归再返回的地方也很巧妙,使得循环能及时回到恰当的位置,只进行一次遍历!function函数传递的是一个vector型的{}一直都没有学习过~
3:有关符号的巧妙运算,-号的时候添加-num,使得最终只用简单的相+操作也很简便!

代码

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 返回表达式的值
     * @param s string字符串 待计算的表达式
     * @return int整型
     */

    vector<int >function(string s,int index){
        stack<int >stack;
        int num=0;
        char op='+';
        int i;
        for(i=index;i<s.length();i++){
            if(isdigit(s[i])){
                num=num*10+s[i]-'0';
                if(i!=s.length()-1)
                    continue;
            }
            if(s[i]=='('){
                vector<int >res=function(s, i+1);
                num=res[0];
                i=res[1];
                if(i!=s.length()-1)
                    continue;
            }
            switch(op){
                case '+':
                    stack.push(num);
                    break;
                case '-':
                    stack.push(-num);
                    break;
                case '*':
                    int temp=stack.top();
                    stack.pop();
                    stack.push(temp*num);
                    break;
            }
            num=0;
            if(s[i]==')')
                break;
            else
                op=s[i];
        }
        int sum=0;
            while(!stack.empty()){
                sum+=stack.top();
                stack.pop();
            }
        return vector<int >{sum,i};
        
    }
    int solve(string s) {
        // write code here
        return function(s,0)[0];
    }
};

题目3(数据流中的中位数)

在这里插入图片描述

收获

1:这道题觉得出的很有趣,对每次输入的字符一次性的进行处理,在入vector的时候顺便排一下序,学会了巧用insert方法~
2:在依次获取中位数的时候,巧用double也熟练了自己对另一个数据类型的使用方法和转换~

代码

class Solution {
public:
    vector<int >res;
    void Insert(int num) {
        if(res.size()==0){
            res.push_back(num);
        }else{
            int i=0;
            for(;i<res.size();i++)
            {
                if(num<=res[i])
                    break;
            }
            res.insert(res.begin()+i, num);
        }
    }
    //这道题好像对double类型的理解又深入了些,最开始对偶数个取中位数的时候直接对相加
    //除2的结果取中位数,殊不知/2本身已经完成了取整的操作,所以一定要从根本上对每个
    //值进行数据类型转换,这样才能得到真正的浮点数结果~
    double GetMedian() { 
        if(res.size()%2==0){
            return (double(res[res.size()/2])+double(res[res.size()/2-1]))/2;
        }else{
            return double(res[res.size()/2]);
        }
    }

};

题目4(最小的K个数)

在这里插入图片描述

收获

1:做这道题真的给我一种恍然大悟的感觉!原来自己一直觉得好神奇好难创建的堆,C++中的priority_queue函数就可以基本完成!
2:统计一下该题的方法使用优先队列,队列中一直要排序的就是留下最小的值,采用大根堆的方法,队头是最大的元素,对每一个新来的元素如果其小于队里最大的元素,它就可以入队,队里那个即将要第一个出去的元素就出去,遍历完所有元素之后就可以得到队列的就都是最小的元素,而队首要出去的第一个元素就是第K小的元素,队内的元素都是所求的!
3:如果要找最大的K个元素,就要采用小跟堆的方法,使得队头是最小的那个,对每一个新来的元素进行比较,如果其比队头大,那么它就可以入队列,最后遍历结束后,队首也是那个第K大的元素!
4:口诀:找第K小的使用大根堆,找第K大的使用小跟堆

代码

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int >res;
        if(k==0||input.size()==0)
            return res;
        //这道题学会了有关建堆的基本使用,原来使用C++的STL建堆是这么容易~
        //这个priority_queue类型对应的是优先队列,首先出队列的都是优先级最高的,
        //如果是大根堆的话,则队首就是最大值,这里默认就是最大值,如果想要它优先级最高的
        //的是最小值的话就要这样创建priority_queue<int,vector<int> , greater<>>q;
        //其中第二个参数是保存数据的容器不能省略~learn it!
        priority_queue<int >q;
        for(int i=0;i<k;i++)
            q.push(input[i]);
        for(int i=k;i<input.size();i++){
            if(q.top()>input[i]){
                q.pop();
                q.push(input[i]);
            }
        }
        for(int i=0;i<k;i++)
        {
            res.push_back(q.top());
            q.pop();
        }
        return res;
    }
};

题目5(寻找第K大)

在这里插入图片描述

收获

1:这道题自己也算用了3种方法实现,第一种是给的标准答案,但是在运算的时候一直卡在了基本有序的时候快排会退化为n²,导致一直超时过不去,后来就看了看大家的建议使用了2、3种果然过这里的系统还是可以的,但是还是重点要学习一下快排的思想,想一下它以后的拓展性应用~
2:这道题可以理解为快排递归的应用,寻找第K大,就将数组进行排序,每一次确定一个下标,如果该次确定下标的位置正好是K的话就是我们想找的元素了,因为快排就是每次递归确定一个值的恰当位置,如果采用从大到小排序的话,其在K位置,就是我们要找到的值了,排序部分设置一个哨兵不变,从后向前以及从前向后遍历,确定位置,不符合要求则寻找还差多少继续遍历!如果只是单纯的想要把所有数都排好序的话,就需要在确定好基准位置之后继续递归前面和后面的数组,直到全部完成~

代码

class Solution {
public:
//     int partition(vector<int >&a,int low,int high){
// //         每一次划分都能返回最low值恰当的位置,采用从大到小的形式排序!
//         int temp=a[low];
//         while(low<high){
//             while(low<high&&a[high]<=temp)
//                 high--;
//             if(low==high)
//                 break;
//             else
//                 a[low]=a[high];
//             while(low<high&&a[low]>=temp)
//                 low++;
//             if(low==high)
//                 break;
//             else
//                 a[high]=a[low];
//         }
//         a[low]=temp;
//         return low;
//     }
//     int quickSort(vector<int >&a,int low,int high,int k){
//         int p=partition(a, low, high);
//         if(k==p-low+1)
//             return a[p];
//         else if (p-low+1>k)
//             return quickSort(a, low, p-1, k);
//         else
//             return quickSort(a, p+1, high, k-(p-low+1));
//     }
//     int findKth(vector<int> a, int n, int k) {
//         // write code here
//         return quickSort(a, 0,n-1,k);
//     }
    //直接sort竟然过了
//     int findKth(vector<int> a, int n, int k) {
//         // write code here
//         sort(a.begin(),a.end());
//         return a[n-k];
//     }
    
    //构建大小为k的大跟堆,好神奇的大小跟堆!记得总结一下!
    int findKth(vector<int> a, int n, int k) {
        // write code here
        priority_queue<int,vector<int> , greater<>>q;
        for(int i=0;i<k;i++)
            q.push(a[i]);
        for(int i=k;i<n;i++){
            if(a[i]>q.top()){
                q.pop();
                q.push(a[i]);
            }
        }
        return q.top();
    }
    
};

题目6(滑动窗口的最大值)

在这里插入图片描述

收获

1:这道题理解起来很简单就是一直滑动着窗口找到其中的最大值!前面有一道关于数据流中中位数的方法那道题,觉得很像,但是突然感觉还是有一丢丢不同,那个流是不抛弃前面的,这个是需要抛弃前面的
2:有点像自己当时用python处理的滑动窗口,当时是设置了一个前面的标志和后面的标志,然后记录到最大值的位置进行划分,这道题呢好像也可以设置一个前面和后面的标志,然后遍历标志内部,找到最大值,就是在窗口很大的时候时间复杂度接近于n²,应该可以同时存储最大值以及最大值的下标,如果其不小于接下来要出去的那个值的下标则保留其最大值,用作后续判断,如果其小于的话后续的最大值就可以选择一个新的位置继续重新遍历窗口大小进行寻找
3:以上的方法相比于直接用双向队列来说可能复杂度会高一些但是应该也是可行的~(在后面)

代码

class Solution {
public:
    //自己先总体总结一下思路!使用双向队列,队首出去过期的窗口值,队尾进入新的最大值的i
    //在每一次进入之前都有先判断一下当前要进入的值和队尾的大小关系,如果比它大就把队尾
    //弹出,如果小的话则直接进入
    vector<int> maxInWindows(const vector<int>& nums, int size) {
        vector<int >res;
        if(size<=nums.size()&&size!=0){
            deque<int >dq;
//             先遍历一个窗口
            for(int i=0;i<size;i++){
                while(!dq.empty()&&nums[dq.back()]<nums[i])
                    dq.pop_back();
                dq.push_back(i);
            }
            for(int i=size;i<nums.size();i++){
                res.push_back(nums[dq.front()]);
                //弹出窗口移走后的值
                while(!dq.empty()&&dq.front()<(i-size+1))
                    dq.pop_front();
                //加入新的值前,去掉比自己先进队列的小于自己的值!
                //此话意味深长~~有点聪明!!!!!!
                while(!dq.empty()&&nums[dq.back()]<nums[i])
                    dq.pop_back();
                dq.push_back(i);
            }
            res.push_back(nums[dq.front()]);
        }
        return res;
    }
};
class Solution {
public:
    vector<int> maxInWindows(const vector<int>& nums, int size) {
        vector<int >res;
        if(size==0||size>nums.size())
            return res;
        int left=0,right=size-1;
        int maxN=nums[0];
        int flag=0;
        int i;
        for(i=left;i<=right;i++){
                if(nums[i]>maxN){
                    flag=i;
                    maxN=nums[i];
                }
            }
        while(right<nums.size()){
            res.push_back(maxN);
            if(flag==left)
            {
                maxN=nums[left+1];
                flag=left+1;
                left++;
                right++;
                for(i=left;i<=right;i++){
                if(nums[i]>maxN){
                    flag=i;
                    maxN=nums[i];
                }
            }
            }else{
                left++;
                right++;
                if(nums[right]>maxN){
                    flag=right;
                    maxN=nums[right];
                }  
            }
            
        }
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值