递归实现字符串最小覆盖窗口时遇递归深度超出错误求助
解决递归深度超限问题及最小覆盖子串实现
错误原因分析
你的makeWindow递归函数存在逻辑缺陷,导致无法触发终止条件,进而无限递归:
charRemain = setOfallCharacter ^ remainLimChar的逻辑错误:异或操作返回的是两个集合的对称差集(只在其中一个集合出现的元素),这不是你需要的「剩余未找到的字符」,正确的剩余字符应该是remainLimChar - setOfallCharacter。- 递归调用时传递的
str1[lenRemain:]会不断缩短字符串,但如果剩余字符串中没有需要的字符,charRemain永远不为空,递归会无限进行,直到触发Python默认的递归深度上限。
修复后的递归实现(不推荐,仍有效率问题)
如果坚持用递归,需要修正逻辑,确保每次递归都能正确减少剩余需要查找的字符,同时处理字符串耗尽的边界情况:
from collections import Counter def smallestWin(str1): all_chars = set(str1) min_window = None # 遍历所有可能的起始位置 for i in range(len(str1)): window = makeWindow(str1[i:], all_chars.copy()) if window: if not min_window or len(window) < len(min_window): min_window = window print(min_window) def makeWindow(s, remain_chars): # 终止条件:找到所有字符,或者字符串耗尽 if not remain_chars: return "" if not s: return None # 表示无法找到剩余字符 current_char = s[0] # 如果当前字符是需要找的,从剩余集合中移除 if current_char in remain_chars: remain_chars.remove(current_char) # 递归处理剩余字符串 rest_window = makeWindow(s[1:], remain_chars) if rest_window is None: return None return current_char + rest_window def main(): str1 = "asdaewsqgtwwsa" smallestWin(str1) if __name__ == "__main__": main()
更优方案:滑动窗口(双指针)法
递归并不适合这类问题,滑动窗口是找最小覆盖子串的标准高效解法,时间复杂度O(n),完全避免递归深度问题:
from collections import Counter def smallestWin(str1): # 统计所有需要包含的字符及其数量 target = Counter(str1) required = len(target) # 滑动窗口的左右指针 left, right = 0, 0 # 记录窗口中已满足数量要求的字符数 formed = 0 # 记录窗口内字符的计数 window_counts = {} # 存储最小窗口的信息:长度,左端点,右端点 min_window = float("inf"), None, None while right < len(str1): char = str1[right] window_counts[char] = window_counts.get(char, 0) + 1 # 如果当前字符的数量达到目标要求,formed加1 if window_counts[char] == target[char]: formed += 1 # 当窗口包含所有字符时,尝试缩小左边界以找到更小窗口 while left <= right and formed == required: char = str1[left] # 更新最小窗口 current_window_len = right - left + 1 if current_window_len < min_window[0]: min_window = (current_window_len, left, right) # 移除左指针的字符,更新窗口计数 window_counts[char] -= 1 if window_counts[char] < target[char]: formed -= 1 left += 1 right += 1 # 返回最小窗口,若不存在则返回空字符串 return str1[min_window[1]:min_window[2]+1] if min_window[0] != float("inf") else "" def main(): str1 = "asdaewsqgtwwsa" print(smallestWin(str1)) if __name__ == "__main__": main()
说明
滑动窗口通过左右指针动态调整窗口大小,在一次遍历中找到最小覆盖子串,既解决了递归深度问题,又大幅提升了运行效率。递归方案虽能修复,但对于较长字符串仍会出现性能瓶颈,因此更推荐滑动窗口解法。
内容的提问来源于stack exchange,提问作者Kise Nguyen
相关产品推荐
相关产品推荐

