最长有效括号子串的变种——最多允许k次失配的最长有效括号子串
字数 853 2025-11-02 10:11:21

最长有效括号子串的变种——最多允许k次失配的最长有效括号子串

题目描述
给定一个只包含'('和')'的字符串s和一个非负整数k,找到最长的子串,使得这个子串在最多修改k个字符(将'('改为')'或将')'改为'(')后可以变成有效的括号字符串。返回这个最长子串的长度。

解题思路
这个问题可以看作是最长有效括号子串问题的扩展,允许最多k次"失配"(即不匹配的括号对)。我们可以使用动态规划结合滑动窗口的方法来解决。

详细步骤

步骤1:问题分析
有效括号字符串需要满足:

  1. 左右括号数量相等
  2. 任意前缀中左括号数量不少于右括号数量

允许最多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]来遍历字符串:

  1. 维护当前窗口的平衡度count(左括号数-右括号数)
  2. 当count < -k时,说明需要修改的括号数超过k,需要收缩左边界
  3. 记录每个平衡度第一次出现的位置
  4. 当遇到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次失配的最长有效括号子串问题。

最长有效括号子串的变种——最多允许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:具体算法实现 步骤5:优化算法 上面的算法时间复杂度是O(nk),我们可以优化到O(n): 步骤6:算法正确性验证 以s = "()())()", k = 1为例: 整个字符串修改1次(将第3个字符')'改为'(')可以得到"()(())()" 最长有效子串长度为7 步骤7:复杂度分析 时间复杂度:O(n) 空间复杂度:O(n) 这个算法通过滑动窗口和哈希表的结合,高效地解决了允许k次失配的最长有效括号子串问题。