Leetcode 678.有效的括号字符串
题目:
给定一个只包含三种字符的字符串:( ,) 和 *,写一个函数来检验这个字符串是否为有效字符串。有效字符串具有如下规则:
1、任何左括号 ( 必须有相应的右括号 )。
2、任何右括号 ) 必须有相应的左括号 ( 。
3、左括号 ( 必须在对应的右括号之前 )。4、* 可以被视为单个右括号 ) ,或单个左括号 ( ,或一个空字符串。
5、一个空字符串也被视为有效字符串。示例 1:
输入: “()”
输出: True
示例 2: 输入: “(*)”
输出: True
示例 3: 输入: “(*))”
输出: True
注意: 字符串大小将在 [1,100] 范围内。
首先说一下自己看到这道题的想法,首先想到的是使用两个栈,存放 ‘(’ 的栈和存放 ‘*’ 的栈,遍历字符串对每个字符进行判断,如果是左括号,则入左括号栈,星号则入星号栈,如果是右括号首先判断左括号栈是否为空,不为空首先使用左括号来匹配,否则使用星号来匹配,如果两者都为空,则说明没有与右括号匹配的左括号,返回false;遍历字符串后,存在三种情况:
1、星号栈为空,左括号栈不为空,或则,两种都不为空,但是左括号栈的元素数量大于星号栈元素数量,返回false;
2、左括号栈为空,返回true;
3、两者都不为空,且星号栈元素数量大于等于左括号栈 元素数量,然后根据位置来判断,遍历左括号栈,两个栈每次各弹出一个,对位置进行判断,在此时,星号是作为右括号来匹配左括号的,因此星号的位置必须大于左括号的位置。
刚开始写的时候,脑子抽抽了,没反应过来,使用的栈中存储的是char字符(stack),因此没法判断位置,就换了另一种方法,后来看了解析才反应过来,我可以用栈来存储他们的位置啊(stack)!真是傻逼!!!
第一种方法的代码:
bool checkValidString(string s)
{
stack<int> stStar, stBracket;
for(int i = 0; i < s.length(); i++)
{
if(s[i] == '*')
{
stStar.push(i);
}
else if(s[i] == '(')
{
stBracket.push(i);
}
else
{
if(!stStar.empty() | !stBracket.empty())
{
stBracket.empty() ? stStar.pop() : stBracket.pop();
}
else
{
return false;
}
}
}
if((stBracket.size() > stStar.size()))
{
return false;
}
while(!stBracket.empty())
{
if(stStar.top() > stBracket.top())
{
stStar.pop();
stBracket.pop();
}
else
{
return false;
}
}
return true;
}
然后自己又想了另一种方法,只使用一个栈。这个栈用来存放左括号和星号(stack),也是遍历,遇见左括号和星号都统统压栈,遇见右括号则判断栈顶,如果为星号则弹出并记录弹出的星号的数量,直到遇到左括号,弹出左括号,然后再压入弹出的星号。经过遍历之后,栈中只剩下左括号和星号,因此星号就可以作为右括号来使用了。再遍历这个栈,这次要使用一个int类型的变量count来记录弹出的星号的数量,如果栈顶为左括号则判断count是否大于0,如果大于零,count减一并弹出栈顶元素,否则返回false。如果栈顶为星号则将count加一并将栈顶元素弹出。经过遍历之后只剩两种情况,有栈中有左括号,返回false,否则返回true。
pp
第二种方法代码:
bool checkValidString(string s)
stack<char> st;
int count = 0;
for(int i = 0; i < s.length(); i++)
{
if(s[i] == '(' || s[i] == '*')
{
st.push(s[i]);
}
else
{
if(st.empty())
{
return false;
}
while(!st.empty())
{
if(st.top() == '*')
{
count++;
st.pop();
}
else
{
st.pop();
while(count > 0)
{
st.push('*');
count--;
}
break;
}
}
if(count > 0 )
{
count--;
while(count > 0)
{
st.push('*');
count--;
}
}
}
}
count = 0;
while(!st.empty())
{
if(st.top() == '(')
{
if(count == 0)
{
return false;
}
st.pop();
count--;
}
else if(st.top() == '*')
{
count++;
st.pop();
}
}
if(!st.empty())
{
if(st.top() == '(')
{
return false;
}
}
return true;
}
第三种方法是从题解中看到的,太神奇了!!!自己是真想不到。由于星号可以充当左括号也可以充当右括号,因此可以使用两个变量来记录未匹配的左括号的最大数量(maxlb)以及最小数量(minlb)。
遍历字符串:
1、遇到 ‘(’,maxlb和minlb都需要加一。
2、遇到’)’,需要使用左括号来匹配,因此maxlb和minlb都需要减一,但是如果此时minlb为0,则不需要减一,如果maxlb为0,则说明左括号以及充当左括号的星号不够匹配右括号了,返回false;
3、遇到 ‘*’ ,minlb-- maxlb++。分别是星号充当右括号和左括号的情况。当然如果minlb==0,则minlb不变,此时星号充当空字符串。
遍历结束后,minlb为0则返回true,否则返回false。
第三种方法的代码:
bool checkValidString(string s)
{
int minlb = 0, maxlb = 0;
for(int i = 0; i < s.size(); i++)
{
switch(s[i])
{
case '(' :
minlb++;
maxlb++;
break;
case '*' :
minlb > 0 ? --minlb : minlb;
maxlb++;
break;
case ')' :
minlb > 0 ? --minlb : minlb;
if(maxlb > 0)
{
maxlb--;
}
else
{
return false;
}
}
}
return minlb == 0;
}
最后,自己的算法基础一般,难免存在错误,希望各位见谅并联系我修正。