题目

标题和出处

标题:有效括号的嵌套深度

出处:1111. 有效括号的嵌套深度

难度

6 级

题目描述

要求

一个字符串是有效括号字符串,当且仅当该字符串只包含 栈题目:有效括号的嵌套深度 - 图1栈题目:有效括号的嵌套深度 - 图2%22%7D#card=math&code=%5Ctexttt%7B%22%29%22%7D&id=c5t6o),且满足下列条件之一:

  • 字符串是一个空字符串;
  • 字符串可以写为 栈题目:有效括号的嵌套深度 - 图3栈题目:有效括号的嵌套深度 - 图4栈题目:有效括号的嵌套深度 - 图5 字符串连接),其中 栈题目:有效括号的嵌套深度 - 图6栈题目:有效括号的嵌套深度 - 图7 都是有效括号字符串;
  • 字符串可以写为 栈题目:有效括号的嵌套深度 - 图8%7D#card=math&code=%5Ctexttt%7B%28A%29%7D&id=Y3m0g),其中 栈题目:有效括号的嵌套深度 - 图9 是一个有效括号字符串。

对于有效括号字符串 栈题目:有效括号的嵌套深度 - 图10,其嵌套深度 栈题目:有效括号的嵌套深度 - 图11%7D#card=math&code=%5Ctexttt%7Bdepth%28S%29%7D&id=ss1z0) 定义如下:

  • 栈题目:有效括号的嵌套深度 - 图12%7D%20%3D%200#card=math&code=%5Ctexttt%7Bdepth%28%22%22%29%7D%20%3D%200&id=Kdak9);
  • 栈题目:有效括号的嵌套深度 - 图13%20%3D%20max(depth(A)%2C%20depth(B))%7D#card=math&code=%5Ctexttt%7Bdepth%28A%20%2B%20B%29%20%3D%20max%28depth%28A%29%2C%20depth%28B%29%29%7D&id=sgdcE),其中 栈题目:有效括号的嵌套深度 - 图14栈题目:有效括号的嵌套深度 - 图15 都是有效括号字符串;
  • 栈题目:有效括号的嵌套深度 - 图16%22)%20%3D%201%20%2B%20depth(A)%7D#card=math&code=%5Ctexttt%7Bdepth%28%22%28%22%20%2B%20A%20%2B%20%22%29%22%29%20%3D%201%20%2B%20depth%28A%29%7D&id=M9jCJ),其中 栈题目:有效括号的嵌套深度 - 图17 是一个有效括号字符串。

例如,栈题目:有效括号的嵌套深度 - 图18栈题目:有效括号的嵌套深度 - 图19()%22%7D#card=math&code=%5Ctexttt%7B%22%28%29%28%29%22%7D&id=s6iJ8) 和 栈题目:有效括号的嵌套深度 - 图20(()())%22%7D#card=math&code=%5Ctexttt%7B%22%28%29%28%28%29%28%29%29%22%7D&id=FlflB) 是有效括号字符串(嵌套深度分别是 栈题目:有效括号的嵌套深度 - 图21栈题目:有效括号的嵌套深度 - 图22栈题目:有效括号的嵌套深度 - 图23),栈题目:有效括号的嵌套深度 - 图24(%22%7D#card=math&code=%5Ctexttt%7B%22%29%28%22%7D&id=YGdTH) 和 栈题目:有效括号的嵌套深度 - 图25%22%7D#card=math&code=%5Ctexttt%7B%22%28%28%29%22%7D&id=OmYoA) 不是有效括号字符串。

给定一个有效括号字符串 栈题目:有效括号的嵌套深度 - 图26,将其分成两个不相交的子序列 栈题目:有效括号的嵌套深度 - 图27栈题目:有效括号的嵌套深度 - 图28,使得 栈题目:有效括号的嵌套深度 - 图29栈题目:有效括号的嵌套深度 - 图30 是有效括号字符串,且 栈题目:有效括号的嵌套深度 - 图31

选择任意的 栈题目:有效括号的嵌套深度 - 图32栈题目:有效括号的嵌套深度 - 图33 使得 栈题目:有效括号的嵌套深度 - 图34%2C%20depth(B))%7D#card=math&code=%5Ctexttt%7Bmax%28depth%28A%29%2C%20depth%28B%29%29%7D&id=Gojm5) 的值最小。

返回数组 栈题目:有效括号的嵌套深度 - 图35(长度为 栈题目:有效括号的嵌套深度 - 图36),表示选择 栈题目:有效括号的嵌套深度 - 图37栈题目:有效括号的嵌套深度 - 图38 的编码:如果 栈题目:有效括号的嵌套深度 - 图39 分给 栈题目:有效括号的嵌套深度 - 图40栈题目:有效括号的嵌套深度 - 图41,否则 栈题目:有效括号的嵌套深度 - 图42。如果存在多个满足要求的答案,只需返回其中任意一个即可。

示例

示例 1:

输入:栈题目:有效括号的嵌套深度 - 图43())%22%7D#card=math&code=%5Ctexttt%7Bseq%20%3D%20%22%28%28%29%28%29%29%22%7D&id=MWG4K)
输出:栈题目:有效括号的嵌套深度 - 图44

示例 2:

输入:栈题目:有效括号的嵌套深度 - 图45(())()%22%7D#card=math&code=%5Ctexttt%7Bseq%20%3D%20%22%28%29%28%28%29%29%28%29%22%7D&id=T9Vgg)
输出:栈题目:有效括号的嵌套深度 - 图46

数据范围

  • 栈题目:有效括号的嵌套深度 - 图47

解法

思路和算法

在考虑将有效括号字符串分成两个不相交的子序列之前,首先需要考虑每个括号所在的嵌套深度。有效括号字符串中,每个左括号都有一个匹配的右括号,一对匹配的左右括号的嵌套深度相同。

为了计算每个括号所在的嵌套深度,可以使用栈存储左括号,根据栈内元素个数得到嵌套深度。从左到右遍历有效括号字符串 栈题目:有效括号的嵌套深度 - 图48,遇到左括号则将左括号入栈,遇到右括号则将栈顶的左括号出栈,表示当前的右括号和栈顶的左括号匹配。根据嵌套深度的定义,左括号和右括号的嵌套深度分别计算如下:

  • 对于左括号,在入栈操作之后的栈内元素个数为左括号的嵌套深度;
  • 对于右括号,在出栈操作之前的栈内元素个数为右括号的嵌套深度。

明确括号的嵌套深度的计算方法之后,回到原问题,将有效括号字符串 栈题目:有效括号的嵌套深度 - 图49 分成两个不相交的子序列 栈题目:有效括号的嵌套深度 - 图50栈题目:有效括号的嵌套深度 - 图51,使得两个子序列的嵌套深度最小。只要栈内的一半括号属于子序列 栈题目:有效括号的嵌套深度 - 图52,另一半括号属于子序列 栈题目:有效括号的嵌套深度 - 图53,即可满足两个子序列的嵌套深度最小。实现方面,将奇数层的括号分给 栈题目:有效括号的嵌套深度 - 图54,将偶数层的括号分给 栈题目:有效括号的嵌套深度 - 图55 即可。

由于一对匹配的左右括号的嵌套深度相同,因此一对匹配的左右括号一定在同一个子序列中。由此可知,任意一个子序列中的左右括号数量一定相等,且左括号一定出现在与之匹配的右括号之前,因此两个子序列都是有效括号字符串。

由于栈内只存储左括号,因此并不需要真正维护一个栈,只需要记录遍历过程中的嵌套深度即可。

代码

  1. class Solution {
  2. public int[] maxDepthAfterSplit(String seq) {
  3. int length = seq.length();
  4. int[] answer = new int[length];
  5. int depth = 0;
  6. for (int i = 0; i < length; i++) {
  7. if (seq.charAt(i) == '(') {
  8. depth++;
  9. answer[i] = depth % 2 == 1 ? 0 : 1;
  10. } else {
  11. answer[i] = depth % 2 == 1 ? 0 : 1;
  12. depth--;
  13. }
  14. }
  15. return answer;
  16. }
  17. }

复杂度分析

  • 时间复杂度:栈题目:有效括号的嵌套深度 - 图56#card=math&code=O%28n%29&id=yRCg8),其中 栈题目:有效括号的嵌套深度 - 图57 是字符串 栈题目:有效括号的嵌套深度 - 图58 的长度。需要遍历字符串 栈题目:有效括号的嵌套深度 - 图59 一次,每次更新嵌套深度的时间都是 栈题目:有效括号的嵌套深度 - 图60#card=math&code=O%281%29&id=Ve64o)。
  • 空间复杂度:栈题目:有效括号的嵌套深度 - 图61#card=math&code=O%281%29&id=WD44w)。除了返回值以外,使用的空间复杂度是常数。