20. 有效的括号
这道题目是栈的典型应用,总体思路是左括号压栈,右括号判断是否匹配。但是我在写代码时考虑不周到,忽略了不匹配的一种情况可能是栈里面为空,增加条件后,详细代码如下:
class Solution {
public:
bool isValid(string s) {
unordered_map<char,char> map;
map[')'] = '(';
map[']'] = '[';
map['}'] = '{';
stack<char> sta;
for(int i=0;i<s.size();i++)
{
if(s[i]=='('||s[i]=='['||s[i]=='{') sta.push(s[i]);
else
{
if(sta.empty()||map[s[i]]!=sta.top()) return false;
sta.pop();
}
}
return sta.empty();
}
};
这道题目也可以不借助哈希表,一个巧妙的思路是遇到左括号的时候直接压入对应的右括号,这样遇到右括号的时候只需要直接对比相等即可,代码如下:
class Solution {
public:
bool isValid(string s) {
if (s.size() % 2 != 0) return false; // 如果s的长度为奇数,一定不符合要求
stack<char> st;
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(']');
// 第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号 return false
// 第二种情况:遍历字符串匹配的过程中,发现栈里没有我们要匹配的字符。所以return false
else if (st.empty() || st.top() != s[i]) return false;
else st.pop(); // st.top() 与 s[i]相等,栈弹出元素
}
// 第一种情况:此时我们已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false,否则就return true
return st.empty();
}
};
1047. 删除字符串中的所有相邻重复项
这道题目同样也是使用栈来解决,遇到相同的就pop,不相等就push,然后再把栈里的都pop出来进行反转即可,代码如下:
class Solution {
public:
string removeDuplicates(string s) {
stack<char> sta;
string res;
for(int i=0;i<s.size();i++)
{
if(!sta.empty()&& sta.top()==s[i]) sta.pop();
else sta.push(s[i]);
}
while(!sta.empty())
{
res+=(sta.top());
sta.pop();
}
reverse(res.begin(),res.end());
return res;
}
};
遗留问题:为什么在获得res时候,不能使用append()函数呢???
150. 逆波兰表达式求值
这道题目有两个步骤:首先用一个函数把字符转换成数字,接着用栈来保存数字,遇到操作符进行对应计算即可,要注意是第二个pop出来的数是被除数or被乘数。自己实现的详细代码如下:(不简洁)
class Solution {
public:
int stringtoint(string s)
{
int res=0;
int n=1;
for(int i =s.size()-1;i>=0;i--)
{
if(s[i]=='+') break;
else if(s[i]=='-') res = -res;
else
{
res+=(n*(s[i]-'0'));
n*=10;
}
}
return res;
}
int evalRPN(vector<string>& tokens) {
stack<int> sta;
for(int i=0;i<tokens.size();i++)
{
if(tokens[i].size()==1&&(tokens[i]=="+"))
{
long tmp1 = sta.top(); sta.pop();
long tmp2 = sta.top();sta.pop();
tmp2+=tmp1;
sta.push(tmp2);
}
else if(tokens[i].size()==1&&(tokens[i]=="-"))
{
int tmp1 = sta.top(); sta.pop();
int tmp2 = sta.top();sta.pop();
tmp2-=tmp1;
sta.push(tmp2);
}
else if(tokens[i].size()==1&&(tokens[i]=="*"))
{
long tmp1 = sta.top(); sta.pop();
long tmp2 = sta.top();sta.pop();
tmp2*=tmp1;
sta.push(tmp2);
}
else if(tokens[i].size()==1&&(tokens[i]=="/"))
{
int tmp1 = sta.top(); sta.pop();
int tmp2 = sta.top();sta.pop();
tmp2/=tmp1;
sta.push(tmp2);
}
else
{
int tmp = stringtoint(tokens[i]);
sta.push(tmp);
}
}
return sta.top();
}
};
看代码随想录有两点可以精简的地方:
1. 字符转数字有库函数
函数:
int atoi(const char *str): //字符串转int
long atol(const cahr *str): //字符串转long
long long atoll(const cahr *str): //字符串转long long
double atof(const char *str): //字符串转double
2. 每次遇到运算符时的对于栈的压栈和出战操作是一样的 ,不需要重复写四遍,只需要把对应的运算分开写就行,精简后代码如下:
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> sta;
for(int i=0;i<tokens.size();i++)
{
if(tokens[i]=="+"||tokens[i]=="-"||tokens[i]=="*"||tokens[i]=="/")
{
int tmp1 = sta.top(); sta.pop(); //取数1
int tmp2 = sta.top();sta.pop(); //取数2
if(tokens[i]=="+") tmp2+=tmp1;
else if((tokens[i]=="-")) tmp2-=tmp1;
else if(tokens[i]=="*") tmp2*=tmp1;
else if(tokens[i]=="/") tmp2/=tmp1;
sta.push(tmp2); //压入计算完的数
}
else
{
int tmp = stoi(tokens[i]);
sta.push(tmp);
}
}
return sta.top();
}
};
心得:关于栈的经典应用题目,需要熟悉掌握,string的一些api还不够熟悉,之后再进行巩固。