📅  最后修改于: 2023-12-03 15:10:37.785000             🧑  作者: Mango
在字符串处理中,我们经常会遇到需要找到最长的有效子串的长度的问题。有效子串指的是符合括号匹配规则的子串。例如,字符串 "((())())" 中的子串 "((()))" 和 "()" 都是有效子串。
可以使用栈来解决这个问题。遍历字符串,如果遇到左括号,就将其压入栈中。如果遇到右括号,则从栈中弹出一个左括号。如果弹出失败或者栈为空,则说明当前右括号没有匹配的左括号,无效子串的长度为当前已经遍历到的位置与上一次未能匹配的位置的差值。
代码片段:
def longest_valid_substring(s: str) -> int:
stack = [-1] # 栈里面存放未能匹配的左括号的下标
longest_len = 0
for i in range(len(s)):
if s[i] == '(':
stack.append(i) # 将左括号的下标压入栈中
else:
stack.pop() # 弹出栈顶的左括号
if not stack:
# 说明当前右括号没有匹配的左括号
# 将当前已经遍历到的位置加入栈中
stack.append(i)
else:
# 当前右括号与栈顶的左括号匹配
longest_len = max(longest_len, i - stack[-1])
return longest_len
时间复杂度为 O(n),空间复杂度为 O(n)。
我们可以使用动态规划来解决这个问题。状态转移方程为:
$$ dp[i] = \begin{cases}0 & s[i] == ')'\dp[i - 2] + 2 & s[i - 1] == '('\dp[i - dp[i - 1] - 2] + dp[i - 1] + 2 & s[i - dp[i - 1] - 1] == '(' \end{cases} $$
其中 dp[i] 表示以下标 i 结尾的最长有效子串的长度。如果 s[i] 是右括号,最长有效子串肯定以右括号结尾,所以 dp[i] 肯定为 0。如果 s[i - 1] 是左括号,那么 dp[i] 就是 dp[i - 2] 加上 2。如果 s[i - 1] 是右括号,那么我们需要找到与之匹配的左括号,记为 j,那么 dp[i] 就是 dp[j - 1] + (i - j + 1)。
代码片段:
def longest_valid_substring(s: str) -> int:
longest_len = 0
dp = [0] * len(s)
for i in range(1, len(s)):
if s[i] == ')':
if s[i - 1] == '(':
dp[i] = dp[i - 2] + 2
elif i - dp[i - 1] > 0 and s[i - dp[i - 1] - 1] == '(':
dp[i] = dp[i - dp[i - 1] - 2] + dp[i - 1] + 2
longest_len = max(longest_len, dp[i])
return longest_len
时间复杂度为 O(n),空间复杂度为 O(n)。
根据需求,我们可以使用栈或者动态规划来求解最长有效子串的长度。具体的实现方法可以根据个人习惯和场景进行选择。