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)。就按照这样的规则,向后依次遍历。