给定一个包含 '(', ')', '*'三种字符的字符串,其中*可以代替'('、 ')' 或者 空 三种字符,问是否可以替换后使得字符串是括号配对的。
比如: (*)
我们把*替换为空,return true
(*))
我们把*替换为'(',就是匹配的
想法:
我的想法是就像从左到右枚举,维护三个变量分别是 l, r, x, 代表三个字符的数量,以及一个栈,维护栈的原因是因为,我们需要知道括号的位置,因为只知道数量是不够的,比如 "((**" 和 "**((" 一个是true,一个是false
遇到的是')', l++
遇到的是')', 先看l有没有,有的话,弹出一个'(',这个时候可能栈顶不是'(',因此需要一个循环; 如果l没有,就看'*'有没有,有的话就把'*'当成一个'('; 如果这两个都没有,那就 return false
如果遇到的是'*', x++
处理完后,我们需要看栈中留下的字符是否可以满足要求,这个时候栈中只有'('和'*'这两种字符,我们判断下就好了
这是代码:
public boolean checkValidString(String s) {
int l, r, x;
l = r = x = 0;
//0:( 1:) 2:*
Stack<Integer> stack = new Stack<>();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (ch == '(') {
l++;
stack.add(0);
} else if (ch == ')') {
if (l > 0) {
l--;
//pop出一个(
//eg: 处理(*)这种
List<Integer> tmp = new ArrayList<>();
while (stack.peek() != 0) {
tmp.add(stack.pop());
}
stack.pop();
for (int k = tmp.size() - 1; k >= 0; k--) stack.add(tmp.get(k));
} else if (x > 0) {
x--;
//pop的是个*
stack.pop();
} else return false;
} else {
x++;
stack.add(2);
}
}
int n = 0;
while (!stack.empty()) {
Integer pop = stack.pop();
if (pop == 2) n++;
else {
//pop==0:(
if (n > 0) n--;
else return false;
}
}
return true;
}
接下来我看了评论区,有非常容易的解法,并且复杂度是O(N)的,而且也只用了两个变量就完成了解答
它的思路是这样的:
一个变量count,代表未匹配的数量,如果遇到'(', 就加1,遇到')'就减一,但是如果遇到'*'呢,有三种情况加1、不动、减一,也就是说我们到这里会有分叉,如此考虑下去,如果又遇到'*', 每个分叉又会再分叉,但是如果仔细观察的话,会发现他们的值域是个连续的区间,这样的话,我们只用维护可能的最小值和最大值,只要最后能够使得count为0,就存在解。
注意如果high小于0的话,就直接返回false了,因为这个时候所有的*都替换为'('时, 右括号的数量还是比左括号的数量多了,不可能有解了
举个例子吧:
“(**())”
start: low = 0 , 1high = 0
step1: low = high = 1
step2: 这里会有三种情况,如果是'(', 那么count=2, 如果是空字符串,count=1, 如果是')', count=0. count=[0, 1, 2] 因此 low = 0, high = 2
step3:同理,最坏的时候low可能会负数,意味着')'太多了,不能这么替换
lastCount=0, count = [-1, 0, 1]
lastCount=1, count = [0, 1, 2]
lastCount=2, count = [1, 2, 3],
-1是无解的,因此count = [0, 1, 2, 3], low = 0, high = 3
step4:low = 1, high = 4
step5:low = 0, high = 3;
step6:low =max(0, low - 1) = 0, high = 2
最后的count可能值为0, 1, 2包含0,也就是说存在一种替换有解。
public boolean checkValidString(String s) {
int low = 0, high = 0;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '(') {
low++;
high++;
} else if (c == ')') {
if (low > 0) low--;
high--;
} else {
if (low > 0) low--;
high++;
}
if (high < 0) return false;
}
return 0 == low;
}