题目
给出一个字符串 s(仅含有小写英文字母和括号)。
请你按照从括号内到外的顺序,逐层反转每对匹配括号中的字符串,并返回最终的结果。
注意,结果中不应包含任何括号。
方法一:栈
思路
对于括号序列相关的题,通用的解法是用递归或者栈。
从左至右地遍历整个字符串,用字符串 str 来记录当前层所遍历到的小写英文字母。对于当前遍历的字母:
- 如果是左括号:把 str 插入到栈中,并且把 str 置空,进入到下一层
- 如果是右括号:遍历到了右括号,说明当前层的字母已经遍历完了,把 str 反转,并把栈顶的字符串弹出,将反转后的 str 插入到弹出字符串的末尾,将结果赋值给 str
- 如果是小写英文字母:追加到 str 末尾
可以看到,只有在遍历到了右括号(第一个出现的右括号是最里面的)才会对字符串进行操作,这样可以保证能从括号里到外处理字符串
代码实现
import java.util.*;
public class test{ public static void main(String[] args) { Solution solution = new Solution(); System.out.println(solution.reverseParentheses("(u(love)i)")); } }
class Solution{ public String reverseParentheses(String s){ Deque<String> stack = new LinkedList<String>(); StringBuffer sb = new StringBuffer(); for (int i = 0;i < s.length();i++){ char ch = s.charAt(i); if (ch == '('){ stack.push(sb.toString()); sb.setLength(0); }else if (ch == ')'){ sb.reverse(); sb.insert(0, stack.pop()); }else { sb.append(ch); } } return sb.toString(); } }
|
输出结果:
iloveu
算法主体
class Solution{ public String reverseParentheses(String s){ Deque<String> stack = new LinkedList<String>(); StringBuffer sb = new StringBuffer(); for (int i = 0;i < s.length();i++){ char ch = s.charAt(i); if (ch == '('){ stack.push(sb.toString()); sb.setLength(0); }else if (ch == ')'){ sb.reverse(); sb.insert(0, stack.pop()); }else { sb.append(ch); } } return sb.toString(); } }
|
复杂度
时间复杂度:O(n^2^),其中n是字符串长度。栈的最大深度是O(n),每一层处理的时间复杂度主要是反转的时间复杂度,为O(n)。
空间复杂度:O(n),n是字符串长度,在任意时刻,字符串中的任一字符只会被栈中至多一个位置包含一次。
方法二:预处理括号
思路
代码实现
import java.util.*;
public class test{ public static void main(String[] args) { Solution solution = new Solution(); System.out.println(solution.reverseParentheses("(ed(et(oc))el)")); } }
class Solution{ public String reverseParentheses(String s){ int n = s.length(); int[] pair = new int[n]; Deque<Integer> stack = new LinkedList<Integer>(); for (int i = 0; i < n;i++){ if(s.charAt(i) == '('){ stack.push(i); }else if (s.charAt(i) == ')'){
int j = stack.pop(); pair[i] = j; pair[j] = i; } }
StringBuffer sb = new StringBuffer(); int index = 0, step = 1; while (index < n){ if (s.charAt(index) == '(' || s.charAt(index) == ')'){ index = pair[index]; step = -step; }else { sb.append(s.charAt(index)); } index += step; } return sb.toString(); } }
|
遇到括号就跳转到对应括号后反向遍历,这个方法很巧妙,反转即是逆向的遍历这个思想
输出结果:
leetcode
算法主体
class Solution{ public String reverseParentheses(String s){ int n = s.length(); int[] pair = new int[n]; Deque<Integer> stack = new LinkedList<Integer>(); for (int i = 0; i < n;i++){ if(s.charAt(i) == '('){ stack.push(i); }else if (s.charAt(i) == ')'){
int j = stack.pop(); pair[i] = j; pair[j] = i; } }
StringBuffer sb = new StringBuffer(); int index = 0, step = 1; while (index < n){ if (s.charAt(index) == '(' || s.charAt(index) == ')'){ index = pair[index]; step = -step; }else { sb.append(s.charAt(index)); } index += step; } return sb.toString(); } }
|
复杂度
时间复杂度:O(n),其中 n 为字符串的长度。预处理出括号的对应关系的序列的时间复杂度为 O(n),遍历字符串的时间复杂度同样为 O(n)。
空间复杂度:O(n),其中 n 为字符串的长度。栈的大小不会超过 n,以及我们需要 O(n) 的空间记录括号的对应关系。