最长有效括号子串的变种——最多允许k次失配的最长有效括号子串
字数 853 2025-11-02 10:11:21
最长有效括号子串的变种——最多允许k次失配的最长有效括号子串
题目描述
给定一个只包含'('和')'的字符串s和一个非负整数k,找到最长的子串,使得这个子串在最多修改k个字符(将'('改为')'或将')'改为'(')后可以变成有效的括号字符串。返回这个最长子串的长度。
解题思路
这个问题可以看作是最长有效括号子串问题的扩展,允许最多k次"失配"(即不匹配的括号对)。我们可以使用动态规划结合滑动窗口的方法来解决。
详细步骤
步骤1:问题分析
有效括号字符串需要满足:
- 左右括号数量相等
- 任意前缀中左括号数量不少于右括号数量
允许最多k次修改意味着:在子串中,我们可以容忍最多k个位置不满足完美匹配条件。
步骤2:定义状态
定义dp[i]表示以第i个字符结尾的子串中,左括号与右括号的数量差(左括号比右括号多的数量)。
更精确地说,对于子串s[j...i]:
- 如果s[i]是'(',计数+1
- 如果s[i]是')',计数-1
我们需要找到最长的子串s[j...i],使得存在某个j ≤ l ≤ i,从j到l的计数始终非负,且整个子串的计数为0,最多允许k次修改。
步骤3:滑动窗口方法
使用滑动窗口[j, i]来遍历字符串:
- 维护当前窗口的平衡度count(左括号数-右括号数)
- 当count < -k时,说明需要修改的括号数超过k,需要收缩左边界
- 记录每个平衡度第一次出现的位置
- 当遇到count曾经出现过的值时,说明中间的子串平衡度为0
步骤4:具体算法实现
def longestValidParenthesesK(s: str, k: int) -> int:
n = len(s)
max_len = 0
# 记录每个平衡度第一次出现的位置
first_occurrence = {0: -1}
count = 0
for i in range(n):
# 更新当前平衡度
if s[i] == '(':
count += 1
else:
count -= 1
# 检查所有可能的平衡度偏移(考虑最多k次修改)
for offset in range(-k, k + 1):
target = count + offset
if target in first_occurrence:
max_len = max(max_len, i - first_occurrence[target])
# 记录当前平衡度的第一次出现位置
if count not in first_occurrence:
first_occurrence[count] = i
return max_len
步骤5:优化算法
上面的算法时间复杂度是O(nk),我们可以优化到O(n):
def longestValidParenthesesK_optimized(s: str, k: int) -> int:
n = len(s)
max_len = 0
# 记录每个平衡度第一次出现的位置
first_occurrence = {0: -1}
count = 0
# 记录不平衡度的累计值
imbalance = 0
left = 0
for right in range(n):
# 更新当前平衡度
if s[right] == '(':
count += 1
else:
count -= 1
# 如果当前字符导致不平衡,更新不平衡度
if (s[right] == ')' and count < 0) or (s[right] == '(' and count > 0):
imbalance += 1
# 当不平衡度超过k时,移动左指针
while imbalance > k and left <= right:
if s[left] == '(':
count -= 1
else:
count += 1
# 更新不平衡度
if left < right:
if (s[left] == '(' and count >= 0) or (s[left] == ')' and count <= 0):
imbalance -= 1
left += 1
# 记录当前平衡度的位置
if count not in first_occurrence:
first_occurrence[count] = right
else:
max_len = max(max_len, right - first_occurrence[count])
return max_len
步骤6:算法正确性验证
以s = "()())()", k = 1为例:
- 整个字符串修改1次(将第3个字符')'改为'(')可以得到"()(())()"
- 最长有效子串长度为7
步骤7:复杂度分析
- 时间复杂度:O(n)
- 空间复杂度:O(n)
这个算法通过滑动窗口和哈希表的结合,高效地解决了允许k次失配的最长有效括号子串问题。