2116. 判断一个括号字符串是否有效(中等)twice

1,问题描述

2116. 判断一个括号字符串是否有效

难度:中等

一个括号字符串是只由 '('')' 组成的 非空 字符串。如果一个字符串满足下面 任意 一个条件,那么它就是有效的:

  • 字符串为 ().
  • 它可以表示为 ABAB 连接),其中AB 都是有效括号字符串。
  • 它可以表示为 (A) ,其中 A 是一个有效括号字符串。

给你一个括号字符串 s 和一个字符串 locked ,两者长度都为 nlocked 是一个二进制字符串,只包含 '0''1' 。对于 locked每一个 下标 i

  • 如果 locked[i]'1' ,你 不能 改变 s[i]
  • 如果 locked[i]'0' ,你 可以s[i] 变为 '(' 或者 ')'

如果你可以将 s 变为有效括号字符串,请你返回 true ,否则返回 false

示例 1:

img

1
2
3
4
输入:s = "))()))", locked = "010100"
输出:true
解释:locked[1] == '1' 和 locked[3] == '1' ,所以我们无法改变 s[1] 或者 s[3] 。
我们可以将 s[0] 和 s[4] 变为 '(' ,不改变 s[2] 和 s[5] ,使 s 变为有效字符串。

示例 2:

1
2
3
输入:s = "()()", locked = "0000"
输出:true
解释:我们不需要做任何改变,因为 s 已经是有效字符串了。

示例 3:

1
2
3
4
输入:s = ")", locked = "0"
输出:false
解释:locked 允许改变 s[0] 。
但无论将 s[0] 变为 '(' 或者 ')' 都无法使 s 变为有效字符串。

示例 4:

1
2
3
4
输入:s = "(((())(((())", locked = "111111010111"
输出:true
解释:locked 允许我们改变 s[6] 和 s[8]。
我们将 s[6] 和 s[8] 改为 ')' 使 s 变为有效字符串。

提示:

  • n == s.length == locked.length
  • 1 <= n <= 105
  • s[i] 要么是 '(' 要么是 ')'
  • locked[i] 要么是 '0' 要么是 '1'

2,初步思考

​ 我自己使用的是双栈进行求解的,但是官方的求解方式更优秀!

3,代码处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import java.util.ArrayDeque;
import java.util.Deque;


public class _2116判断一个括号字符串是否有效 {

// stack求解
// Pair<Character,Integer> 表示当前字符和当前字符的索引
// 直接无视掉可以修改的符号
public boolean canBeValid_gov(String s, String locked) {
int n = s.length();
int mx = 0; // 可以达到的最大分数
int mn = 0; // 可以达到的最小分数 与 最小有效前缀对应分数 的较大值
for (int i = 0; i < n; ++i) {
if (locked.charAt(i) == '1') {
// 此时对应字符无法更改
int diff;
if (s.charAt(i) == '(') {
diff = 1;
} else {
diff = -1;
}
mx += diff;
mn = Math.max(mn + diff, (i + 1) % 2);
} else {
// 此时对应字符可以更改
++mx;
mn = Math.max(mn - 1, (i + 1) % 2);
}
if (mx < mn) {
// 此时该前缀无法变为有效前缀
return false;
}
}
// 最终确定 s 能否通过变换使得分数为 0(成为有效字符串)
return mn == 0;
}

// 利用双栈来进行处理
public boolean canBeValid_stack(String s, String locked) {
char[] charArrayS = s.toCharArray();
char[] charArrayL = locked.toCharArray();
int n = charArrayS.length;
if (n % 2 == 1) return false;// 奇数肯定不行
Deque<Integer> stackChange = new ArrayDeque<>();// 可变对象
Deque<Integer> stackA = new ArrayDeque<>();// 左括号
for (int i = 0; i < n; i++) {
if (charArrayL[i] == '0') {// 可变的直接计数
stackChange.add(i);
} else {// 不可变
if (charArrayS[i] == '(') {
stackA.add(i);
} else {// 右括号
if (!stackA.isEmpty()) {
stackA.pollLast();
} else if (!stackChange.isEmpty()) {
stackChange.pollLast();
} else {
return false;
}
}
}
}
while (!stackA.isEmpty() && !stackChange.isEmpty()) {
if (stackA.pollLast() > stackChange.pollLast()) {
return false;
}
}
return stackA.isEmpty();// 不能多出(
}

public static void main(String[] args) {
System.out.println(new _2116判断一个括号字符串是否有效().canBeValid_stack("(((())(((())", "111111010111"));
// System.out.println(new _2116判断一个括号字符串是否有效().canBeValid_stack("))()))", "010100"));
// System.out.println(new _2116判断一个括号字符串是否有效().canBeValid_stack("())(()(()(())()())(())((())(()())((())))))(((((((())(()))))(", "100011110110011011010111100111011101111110000101001101001111"));
}
}
/**
* ))())),aCnt = 1,bCnt = 5
*/