您的位置:首页 > 其它

leetcode刷题,总结,记录,备忘 301

2016-05-02 20:23 351 查看
leetcode301Remove Invalid Parentheses

Remove the minimum number of invalid parentheses in order to make the input string valid. Return all possible results.

Note: The input string may contain letters other than the parentheses 
(
 and 
)
.

Examples:

"()())()" -> ["()()()", "(())()"]
"(a)())()" -> ["(a)()()", "(a())()"]
")(" -> [""]


Credits:

Special thanks to @hpplayer for adding this problem and creating all test cases.

Subscribe to see which companies asked this question

这是一道hard题,真的很难,我上个月刚解决他,一直没来得及写在博客中,今天就来好好分析下。虽然这个题目的通过率是百分之30,但是我一共提交20多次才通过,因为有些测试用例比较特殊,所以一直对自己算法改来改去。首先先把代码整体放上来,再仔细分析。

class Solution {
public:
vector<string> vs;
vector<int> itemp;
string head;
string tail;

void function(string s, int start, int startopp, int deep, int deepopp, char tar, char opp)
{
if (deep == 0)
{
if (deepopp == 0)
{
int flag = 0;
for (int i = 0; i < s.size(); ++i)
{
if (s[i] == '(')
{
flag++;
}
else if (s[i] == ')')
{
flag--;
}
if (flag < 0)
{
return;
}
}

vs.push_back(head + s + tail);

return;
}
for (int i = startopp; i < s.size(); ++i)
{
if(s[i] == opp)
{
string temp = s;
temp.erase(i, 1);
function(temp, i, startopp, deep, deepopp - 1, tar, opp);
}
}
}

for (int i = start; i < s.size(); ++i)
{
if(s[i] == tar)
{
string temp = s;
temp.erase(i, 1);
function(temp, i, startopp, deep - 1, deepopp, tar, opp);
}
}
}

vector<string> removeInvalidParentheses(string s) {
if (s.size() == 0)
{
vs.push_back("");
return vs;
}

while (s.size() != 0 && (s[0] == ')' || s[s.size() - 1] == '(' || isalpha(s[0]) || isalpha(s[s.size() - 1])))
{
if (s[0] == ')')
{
s.erase(0, 1);
continue;
}
if (s[s.size() - 1] == '(')
{
s.erase(s.size() - 1, 1);
continue;
}
if (isalpha(s[0]))
{
head = head + s[0];
s.erase(0, 1);
continue;
}
if (isalpha(s[s.size() - 1]))
{
tail = s[s.size() - 1] + tail;
s.erase(s.size() - 1, 1);
continue;
}
}

int flag = 0;
char target;
char opp;
int min_right = 0;
int max_left = 0;
int deepopp = 0;
int index_right = -1;

for (int i = 0; i < s.size(); ++i)
{
if (s[i] == '(')
{
flag++;
}
else if (s[i] == ')')
{
flag--;
}
if (flag > max_left)
{
max_left = flag;
}
if (flag < min_right)
{
min_right = flag;
index_right = i;
}
}

if (flag == 0)
{
int f = 0;
for (int i = index_right + 1; i < s.size(); ++i)
{
if (s[i] == '(')
{
f++;
}
else if (s[i] == ')')
{
f--;
}
}

if (f > 0)
{
deepopp = f;
}
else
{
deepopp = 0;
}

if (deepopp == 0)
{
s = head + s + tail;
vs.push_back(s);
return vs;
}
else
{
target = '(';
opp = ')';
}
}
else if (flag > 0)
{
target = '(';
opp = ')';
deepopp = min_right;
}
else if (flag < 0)
{
target = ')';
opp = '(';
int f = 0;
for (int i = index_right + 1; i < s.size(); ++i)
{
if (s[i] == '(')
{
f++;
}
else if (s[i] == ')')
{
f--;
}
}
if (f > 0)
{
deepopp = f;
}
else
{
deepopp = 0;
}
}

function(s, 0, 0, abs(flag) + abs(deepopp), abs(deepopp),  target, opp);

set<string> set_s(vs.begin(), vs.end());
vector<string> res(set_s.begin(), set_s.end());

return res;

}
};
算法的一开始,首先我们需要剔除一些可能的输入字符串的情况,保证我们开始处理的字符串是由'('开头,由')'结尾的,如果左边的开头是')'或者右边的结尾是'('就直接先删除掉,不用管,如果开头和结尾是字母的话,就分别删除掉,然后保存在单独的2个字符串中,在最终的结果中分别在头尾部分添加上去,一直进行这样的循环,直到符合我们的条件由'('开头,由')'结尾,然后进行下一步工作。

接着是对已经处理过的字符串的一个遍历工作,声明一个int变量,用来记录这个字符串中,到底出现过多少次'('和')',最后通过flag是正还是负来判断这个字符串中是'('多还是')'多。遍历完字符串之后的部分是重点部分,也是整个算法的关键。有3种情况,flag等于0,flag大于0,flag小于0,我必须说的是,flag大于0的情况是最容易的,所以我们先搁置,看下其他2种情况。

flag小于0的时候,表示字符串中')'的个数过多,需要删除多余的')',但是有一种情况比如"()))))(()",这样的结果flag会等于-3,那我们就以为是多了3个')',直接使用深度优先算法,对字符串中的各种3个')'的组合删掉就行了。理论上是如此,但是实际上,由于在字符串后面的部分,出现了"(()"这样的情况,所以如果单纯的进行以')'为目标的删除,结果不是正确的,可能会有这样的结果"())(()",必然是错误的,所以如果对于flag<0的情况,首先在上一层进行遍历字符串的时候,必须记录下出现')'最大值时下标索引,然后在后续过程中以该索引为起点,计算是否有过多的'('出现,记录下数值为deepoop,再次之后调用深度优先的函数,2个深度参数分别为abs(flag)
+ abs(deepopp)和abs(deepopp),分别表示')'和'('需要删除的个数,在深度优先函数中进行分别删除,最终得到的结果才是正确的,使用深度优先剔除字符的函数我们后面再说。

flag==0的时候,此时并不能以为这个字符串就是正确的了,比如"())(()"这样虽然flag=0,但是并不是正确的。所以我们需要从之前遍历字符串时得到的出现最大次数')'的下标索引,以这个为起始点,进行遍历,其实是可以找到多出的'('的个数,然后相应的')'的个数即abs(flag)需要加上这样的个数,然后在深度优先函数中对其进行剔除。

flag>0的情况就比较简单了,只需得到'('出现最多的次数值即可。

之后来说说深度优先计算剔除字符的函数,无非是使用了2个deep,先将一个字符全部删掉后,再进行另一个字符的删除,有2个判断条件,deep == 0和deepopp == 0,表示在将前一个深度优先遍历结束之后才进行下一次的遍历,就是又套了一层进去。

可能说的不是太好,毕竟是个上个月写的东西了,,时间隔的有点久了,并且鄙人语文水平比较差,可能描述的不好,也只是提出自己的一个解决办法而已,,,说的不好勿喷。关键还是需要靠自己想出一个方法,然后在自己的思路上一步一步去深入解决这个问题,这是我做这道题的体会,因为一开始自己有点想法,虽然很多次都没提交过去,但是一直靠自己一点一点分析每个测试用例,最终通过,而没有直接去翻别人的东西,自己思考很重要,这是我做这道题得到的经验。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: