📜  门| Sudo GATE 2021 测验 |第 47 题(1)

📅  最后修改于: 2023-12-03 14:58:34.357000             🧑  作者: Mango

Sudo GATE 2021 测试 | 第 47 题

题目描述

给定一个长度为 N 的字符串 S,由 '(', ')' 和 '|' 构成,满足 S 中任意一个 '(' 对应的 ')' 位置一定严格在 S 中此 '(' 的右侧,且 '|' 可以将字符串分为左右两部分。定义一个括号匹配的操作为将字符串 S 中某个左右括号匹配对中间的子字符串替换成 ' () '。

现在考虑一种新的括号匹配的操作,定义为将字符串 S 中某个左右括号匹配对中间的子字符串替换成 '门' 或者 '()' 或者 ' 门门 '。

给定一个字符串 S,求通过该新的括号匹配操作最少需要几次可以将 S 变成一个长度为 1 的字符串。

$$ \texttt{Input :} $$

第一行包含一个整数 T,表示数据组数。

对于每组数据,第一行包含一个整数 N。

第二行包含一个长度为 N 的字符串 S。

$$ \texttt{Output :} $$

对于每组数据,输出一行一个整数,表示最少需要的操作次数。

$$ \texttt{Constraints :} $$

$1 \leq T \leq 10^3, 1 \leq N \leq 10^6$

$$ \texttt{Example :} $$

$$ \texttt{Input :} $$

2
9
(|()|)
18
()||()|(|()||)|()
$$

$$
\texttt{Output :}
$$

2 4


## 题解

对于每个匹配的括号对,我们可以考虑其中间部分的长度。一开始可以选择将中间部分全部替换成 '()',并记录下来替换的次数,然后再根据题目要求选择进一步替换成合适的 '门' 或 ' 门门 '。

具体来说,我们可以用一个栈来维护每个左括号的位置。遍历字符串,如果遇到左括号就将其位置入栈,遇到右括号就将栈顶部的左括号和当前右括号匹配,替换其中间部分为 '()',并弹出栈顶元素。最终得到的字符串就是最少替换次数的。

接下来是考虑如何选择替换的操作。我们发现,将 '()' 替换成 '门' 可以使得括号对更少,而将 '门' 替换成 ' 门门 ' 可以使得括号对更短。因此,我们可以贪心地进行替换:每次优先选择将 '()' 替换成 '门',如果不能再进行该替换,再选择将 '门' 替换成 ' 门门 '。重复进行该过程,直到不能再进行任何替换。

时间复杂度为 $O(n)$。

### 代码

```python
def minimum_steps(s):
    stack = []
    count = 0
    for i, c in enumerate(s):
        if c == '(':
            stack.append(i)
        elif c == ')':
            j = stack.pop()
            s = s[:j+1] + ')' * (i-j-1) + s[i:]
            count += 1
    while True:
        t = s.replace('()', '门', 1)
        if t != s:
            s = t
            count += 1
        else:
            t = s.replace('门', ' 门门 ', 1)
            if t != s:
                s = t
                count += 1
            else:
                break
    return count

t = int(input())
for _ in range(t):
    n = int(input())
    s = input().strip()
    ans = minimum_steps(s)
    print(ans)

代码解释:

首先定义一个辅助函数 minimum_steps,用来计算最少的操作次数。该函数接受一个字符串 s 作为输入,返回最少的操作次数。

遍历字符串 s,如果遇到左括号就将其位置入栈,遇到右括号就将栈顶部的左括号和当前右括号匹配,并记录下替换成 '()' 的次数。最终得到的字符串就是最少替换次数的。

接下来是贪心地进行替换。用一个 while 循环,每次用 replace 方法将 '()' 替换成 '门',并将替换的次数加入到 count 中。如果不能再进行该替换,再选择将 '门' 替换成 ' 门门 '。重复进行该过程,直到不能再进行任何替换。

最后用一个 for 循环,对每组数据分别计算最少的操作次数,并输出结果。