有效的括号 删除字符串中的所有相邻重复项 逆波兰表达式求值 滑动窗口最大值

1.给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。

有效字符串需满足:

  • 左括号必须用相同类型的右括号闭合。
  • 左括号必须以正确的顺序闭合。
  • 注意空字符串可被认为是有效字符串。

#include <bits/stdc++.h>
using namespace std;
class Solution{
    public:
        bool isvalid(string s)
        {
            stack<char> st;
            if(s.size()%2!=0)
            {
                return false;
            }
            for(int i=0;i<s.size();i++)
            {
                if(s[i]=='(')
                {
                    st.push(')');
                }
                else if(s[i]=='{')
                {
                    st.push('}');
                }
                else if(s[i]=='[')
                {
                    st.push(']');
                }
                else if(st.empty()||s[i]!=st.top())
                {
                    return false;
                }
                else
                {
                    st.pop();
                }
                
            }
            return st.empty();
            
        }
    
    
    
};

int main()
{
    Solution solution;
    cout<<"()"<<" "<<(solution.isvalid("()") ?"有效的括号":"无效的括号")<<endl;
    cout<<"()[]{}"<<" "<<(solution.isvalid("()[]{}") ?"有效的括号":"无效的括号")<<endl;
    cout<<"(]"<<" "<<(solution.isvalid("(]") ?"有效的括号":"无效的括号")<<endl;
    cout<<"([)]"<<" "<<(solution.isvalid("([)]") ?"有效的括号":"无效的括号")<<endl;
    cout<<"{[]}"<<" "<<(solution.isvalid("{[]}") ?"有效的括号":"无效的括号")<<endl;
    return 0;
 } 

思路:这道题是关于括号匹配的,我们可以利用栈来实现。其实三种情况就能包括所有的括号问题,1.左括号的数量多 2.右括号的数量多 3.左右括号的类型不匹配

同时,我们可以根据括号的数量先来进行剪枝,如果括号数量不是偶数,那么肯定是不匹配的。

在开始遍历时,如果遇到了左括号,可以在栈中加入一个同类型的右括号,之后如果遇到了右括号就和栈顶元素比较,此时栈里的括号必定全为右括号,这个时候只需要判断括号类型一致与否。

如果左括号的数量多,那么栈中必定会多一个右括号,因此在对字符串遍历结束之后,栈必定不为空,此时只需返回false。如果右括号的数量多,那么在字符串遍历还没有结束时栈就已经为空了。

2.给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。

在 S 上反复执行重复项删除操作,直到无法继续删除。

在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

#include <bits/stdc++.h>
using namespace std;
class Solution{
    public:
    string remove(string S)
    {
        string result;
        for(char s:S)
        {
            if(result.empty()||result.back()!=s)
            {
                result.push_back(s);
            }
            else
            {
               result.pop_back();
            }
            
        }
        return result;
    }
   
};
int main()
{
    Solution solution;
    cout<<solution.remove("abbar");
    return 0;
    
}
思路:本题本质上其实也是匹配问题,可以借助于栈,也可以用字符串来代替栈。

对所给的字符串进行遍历,将遍历到的字符与新的字符串里的首部字符进行比较,如果相同就将其弹出(push_back),不同就放入到字符串中,遍历完之后就将新的字符串输出(pop_back)。

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

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

说明:

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

#include <bits/stdc++.h>
using namespace std;
class Solution{
    public:
    int eval(vector<string>& s)
    {
        stack<long long> st;
        for(int i=0;i<s.size();i++)
        {
            if(s[i]=="+"||s[i]=="-"||s[i]=="*"||s[i]=="/")
            {
                long long num1=st.top();
                st.pop();
                long long num2=st.top();
                st.pop();
                if(s[i]=="+")
                    st.push(num2+num1);
                if(s[i]=="-")
                    st.push(num2-num1);
                if(s[i]=="*")
                    st.push(num2*num1);
                if(s[i]=="/")
                    st.push(num2/num1);
                
            }
            else
            {
                st.push(stoll(s[i]));
                
            }
            
        }
        long long result=st.top();
        st.pop();
        return result;
    }
    
};
int main()
{
    Solution solution;
    vector<string> str1={"2", "1", "+", "3", "*"};
    vector<string> str2={"4", "13", "5", "/", "+"};
    vector<string> str3={"10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"};
    cout<<solution.eval(str1)<<endl<<solution.eval(str2)<<endl<<solution.eval(str3);
    return 0;

思路:所谓逆波兰表达式其实就是后缀表达式,我们可以利用栈来实现,对表达式进行遍历,当遇到数字时就放于栈中,但切记要用stoll把类型转换成long long,如果遇到的是符号,就从栈中弹出2个数字,进行对应运算,将结果返回到栈中。还有就是,运算的2个数的位置,如果先弹出num2,后弹出num1,进行加法运算,那么结果为num1+num2。

4. 给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回滑动窗口中的最大值。

#include <bits/stdc++.h>
using namespace std;
class Solution{
    private:
    
        class MyQueue{
            public:
                deque<int> que;
                void pop(int value)
                {
                    if(!que.empty()&&value==que.front())
                    {
                        que.pop_front();
                    }
                }
                void push(int value)
                {
                    while(!que.empty()&&value>que.back())
                    {
                        que.pop_back();
                    }
                    que.push_back(value);
                    
                }
            int front()
            {
                return que.front();
                }    
                
            
        };
    public:
       vector<int> maxslidWindow(vector<int>& num,int k)
    {
           MyQueue que;
           vector<int> result;
           for(int i=0;i<k;i++)
           {
               que.push(num[i]);
           }
           result.push_back(que.front());
           for(int i=k;i<num.size();i++)
           {
               que.pop(num[i-k]);
               que.push(num[i]);
               result.push_back(que.front());
           }
           
           return result;
           
    }    
        
};
int main()
{
    Solution solution;
    vector<int> nums={1,3,-1,-3,5,3,6,7};
    vector<int> result=solution.maxslidWindow(nums,3);
    for(int n:result)
    {
        cout<<n<<" ";
    }
    cout<<endl;
    return 0;
}

思路:这道关于滑动窗口的问题,我们使用单调队列(即该队列的元素是单调有序的)来实现,在队列的两端都可以进行添加删除元素。其实,我们主要就是通过3个功能来实现,即pop(),push(),maxslidWindow()。同时,也是为了让单调队列维护最大值,使队列出口端的元素始终是最大值,那么该队列就是单调递减的。

首先对前k个元素进行遍历,将其(value)放入到队列中,但是要满足条件才能进入,即value小于队列入口处的元素,如果value比它们大,就要把队列中的元素pop掉。这就相当于提前做了后面需要pop的操作。这段范围遍历完后,要向后移动滑动窗口,此时就要除去滑动窗口的最前面的元素,相当于是在单调队列中进行pop操作,还要加入滑动窗口后的那一个元素,也相当于在单调队列中进行push操作,最后记录队列中的最大值(que.front)。就按照这样的规则,向后依次遍历。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值