题目:反转一个字符串,如果其中有部分被括号包裹(完整的左右括号才算,且被多重括号包裹,以最外层为准),则这部分当成一个整体内部顺序不变。
例子:
abcd -> dcba
abc(def)g -> g(def)cba 解释:(def)看作一个整体,内部顺序不变
ab(cde -> edc(ba 解释:没有完整括号
abc(de(fgh)i)jk -> kj(de(fgh)i)cba 解释:(de(fgh)i)看作一个整体,内部顺序不变
ab(cde)fg(hij -> jih)gf(cde)ba 解释:(cde)看作一个整体
a(bcd)ef(g((hi)jk -> kj(hi)(g(fe(bcd)a 解释:(bcd)、(hi)看作一个整体
思路:用一个栈结构,遍历输入的字符串,初始n为0,如果为字母则向栈中加入n,如果是括号则加入-n。当遇到左括号时 n+1,遇到右括号时插入后n-1;
遍历完成后,栈中大于n为完整括号中的内容,小于-n的为两边的括号,使用 i 指向字符串末尾,不断取出栈中内容,当判断是完整括号东西时(内容或括号),就用k = i,k-- 直到跳出括号,然后将输入字符串中 k+1, i+1中内容截取到新字符串中,并且让 i = k;
若不是括号相关内容,直接将字符添加到新字符串中,并i--。
补充:在例子5、6中,因为字符串结尾括号未配对,导致n>0,从而影响了之前的括号内容,导致之前括号数字小于等于n,所以当出栈时遇到 n>0且stack.peek() == -n的情况,说明碰到了一个未关闭的左括号,这时n--即可
public class Main {
public static void main(String[] args) {
String str = "a(bcd)ef(g((hi)jk";
String res= reverse(str);
System.out.println();
System.out.println(res);
}
public static String reverse(String input) {
Stack<Character> stack = new Stack<>();
int n = 0;
for (int i = 0; i < input.length(); i++) {
if (input.charAt(i) == '(') {
n++;
stack.push((char) ('0' -n));
} else if (input.charAt(i) == ')') {
stack.push((char) ('0' -n));
if (n > 0) {
n--;
}
} else {
stack.push((char)('0' + n));
}
}
System.out.println("n = " + n);
for (Character c : stack) {
System.out.print(c - '0');
System.out.print(" ");
}
StringBuilder sb = new StringBuilder();
int i = input.length() - 1;
while (!stack.isEmpty()) {
char c = stack.peek();
int d = c - '0';
if ((d >=0 && d <= n) || (d < 0 && d >= -n)) {
if (n > 0 && d == -n) {
n--;
}
stack.pop();
sb.append(input.charAt(i--));
} else {
int k = i;
while (k >= 0) {
c = stack.peek();
d = c - '0';
if ((d >=0 && d > n) || (d < 0 && d < -n)) {
stack.pop();
k--;
} else {
break;
}
}
sb.append(input, k + 1, i+ 1);
i = k;
}
}
return sb.toString();
}
}
结果:
n = 2
0 -1 1 1 1 -1 0 0 -1 1 -2 -3 3 3 -3 2 2 2
kj(hi)(g(fe(bcd)a