看到已有的题解几乎都是栈操作,但是考虑到leetcode的数据量一直都不大,所以跑一般oj10w长度的字符串很难说栈操作会不会超时,因此尝试生成了10w长度的数据,结果果然效率不够高,因此打算来记录一下笔者的解法
以给的范例"(ed(et(oc))el)"为例,从左到右开始计算,e从1到8,d从2到7,e从3到6再到3……以此类推,发现规律,当存在一层括号时,反转,而反转的目标位置,就是括号首位位置相加然后减去字母所在位置,以第三个字母e为例,(1 + 8) - 3为6,(3 + 6) - 6为3,如果写到一个式子里就是(3 + 6) - [(1 + 8) - 3],如果后续再出现括号,以第五个字母o为例,(5 + 6) - {(3 + 6) - [(1 + 8) - 5]}为6,如果一直在括号内移动,那么只需要改变算式中最后一位数即可,因此可以发现规律,将前面所有式子缓存下来作为基,然后每次加或减最后一位(当前位置的序数),即可得到目标位置
然后考虑如何记录所有括号,使用栈操作和一遍遍历的方式,遇到左括号入栈,遇到右括号出栈,如果长度为0则不记录,同时记录括号的左右位置,然后确定一个定理,最小括号内不会存在更小的括号,证明:该括号是最小括号x1,长度为a1,内部存在括号(反括号),则该括号(反括号)与最小括号x1的反括号(括号)形成括号x2,长度为a2,小于a1,因为括号越小,长度越短,矛盾,因此该括号不是最小括号。因此包含中的最小括号是长度最短的括号,笔者使用list记录括号数量,考虑到后续出栈的效率问题,因此对左括号位置进行一次降序排序,左括号越往前,排在越后面,可以直接出栈,然后在左括号位置相同时,对长度进行升序排列,即先运算外层括号
然后考虑右括号的问题,上面已证明和保证,最后入栈的肯定是最小的且最内层的括号,因此,在计算时,查询当前位置是否有反括号,有则直接出栈,同时根据当前运算符号从基中去除掉
大致运算流程如下图所示
时间复杂度:两遍遍历,第一遍找到所有括号组合然后排序(sorted是归并排序),第二遍是逐个计算,对比和出栈的时间非常短,因此可以近似为O(n),实践检验也确实是,以下为三组测试结果,分别对应笔者的算法、标准的栈操作反转和python自带函数[::-1]反转耗时,单位为s
100w字符长度,1w个括号(5k组)
100w字符长度,10w个括号(5w组)
1000w字符长度,10w个括号(5w组)
代码如下:
1 defreverseParentheses(s):2 string_list =[]3 cnt_list = 1
4 bracket_left =[]5 bracket_list =[]6 bracket_list_now =[]7
8 for i inrange(0, len(s)):9 if '(' ==s[i]:10 bracket_left.append(cnt_list)11 elif ')' ==s[i]:12 loc_left =bracket_left.pop()13 loc_right = cnt_list - 1
14 if loc_left <15 bracket_list.append loc_right else:17 string_list.append cnt_list>
19 bracket_list = sorted(bracket_list, key=lambda x: (-x[0], x[2]))20 len_bracket_list =len(bracket_list)21 calc_base =022 #print(bracket_list)
23 #print(string_list)
24
25 positive = 1
26 ans = [0 for i inrange(len(string_list))]27
28 for i inrange(0, len(string_list)):29 ifbracket_list:30 whileTrue:31 if bracket_list and i + 1 == bracket_list[len_bracket_list - 1][0]:32 ifpositive:33 calc_base += bracket_list[len_bracket_list - 1][0] + bracket_list[len_bracket_list - 1][1]34 positive = 1 -positive35 else:36 calc_base -= bracket_list[len_bracket_list - 1][0] + bracket_list[len_bracket_list - 1][1]37 positive = 1 -positive38 bracket_list_now.append(bracket_list[len_bracket_list - 1])39 bracket_list.pop()40 len_bracket_list -= 1
41 else:42 break
43
44 ifpositive:45 ans[calc_base + (i + 1) - 1] =string_list[i]46 else:47 ans[calc_base - (i + 1) - 1] =string_list[i]48
49 ifbracket_list_now:50 len_bracket_list_now =len(bracket_list_now)51 j = len_bracket_list_now - 1
52 while j >=0:53 if i + 1 == bracket_list_now[j][1]:54 temp =bracket_list_now.pop(j)55 ifpositive:56 calc_base += temp[0] + temp[1]57 positive = 1 -positive58 else:59 calc_base -= temp[0] + temp[1]60 positive = 1 -positive61 len_bracket_list_now -= 1
62 j -= 1
63 else:64 break
65 #return ans
66 return "".join(ans)67
68
69 defreverseParentheses2(s):70 while '(' ins:71 s = re.sub(r'(([^()]*))', lambda x: x.group(1)[::-1], s)72 returns73
74
75 defreverseParentheses3(s):76 ans = ['']77 for c ins:78 if c == '(':79 ans += ['']80 elif c == ')':81 ans[-2] += ans[-1][:: -1]82 ans.pop()83 else:84 ans[-1] +=c85 return ans[0]
如有错误,欢迎指正!
15>