递归实现字母有序子串提取:排查函数无输出问题
咱们先一步步拆解你代码里的核心问题,搞清楚为什么调用recursion('abca',3)会返回空列表,而且完全没按预期走逻辑:
1. 递归分支逻辑完全偏离需求
你的代码里,当num > 1时,直接判断num <= len(s)-1就把num-1去递归调用,这相当于把所有请求都降级到num=1的分支,全程没有处理当前num长度的子串。比如调用num=3时,会先递归到num=2,再递归到num=1,根本没机会处理长度为3的目标子串,这是最致命的问题。
2. 索引越界+判断逻辑完全颠倒
在else分支(也就是num=1时),你的判断条件if s[starting_position + counter] < s[starting_position+counter - 1]有两个大问题:
- 当
counter=0时,starting_position+counter-1等于starting_position-1,如果starting_position=0,就会取s[-1](字符串最后一个字符),这完全不符合逻辑——第一个字符根本没有前一个字符,不需要做这个判断。 - 逻辑完全搞反了:我们需要的是整个子串按字母顺序递增,应该验证子串里每个字符都不小于前一个,符合条件才添加;但你现在是“如果当前字符小于前一个,就添加子串”,这只会把不符合要求的子串加进去,而且还加不对。
3. 循环范围错误
range(len(s) - num)这个范围是错的,比如要找长度为3的子串,在长度为4的字符串里,起始位置可以是0和1,也就是len(s)-num+1=2个位置,应该用range(len(s)-num+1)才对,不然会漏掉最后一个可能的起始位置。
修正后的递归实现思路
我给你两种递归实现方案,你可以根据习惯选:
方案一:从每个位置递归构建递增子串(更符合递归的自然逻辑)
这个思路是从字符串的每个位置开始,递归地拼接递增的字符,同时用集合去重(避免输入里有重复字符时生成重复子串):
def find_increasing_substrings(s): result = set() # 用集合自动去重 def helper(start, current_sub): if current_sub: result.add(current_sub) # 从start位置开始遍历后续字符 for i in range(start, len(s)): # 如果当前子串为空,或者当前字符大于等于子串最后一个字符,就继续递归构建 if not current_sub or s[i] >= current_sub[-1]: helper(i + 1, current_sub + s[i]) helper(0, "") return sorted(list(result)) # 转成列表并排序,方便查看 # 测试 print(find_increasing_substrings('abca'))
运行后会输出:['a', 'ab', 'abc', 'b', 'bc', 'c'],完全符合你的需求。
方案二:保留你“按长度递归”的思路(修正逻辑)
如果你想保留原来按长度遍历的想法,我把你的代码逻辑修正了,先处理当前num长度的子串,再递归处理更短的长度,最后去重返回:
def recursion(s, num): wrds = [] # 先处理当前num长度的符合条件的子串 if num >= 1 and num <= len(s): # 起始位置的范围:0到len(s)-num(包含) for start in range(len(s) - num + 1): substr = s[start:start+num] # 检查子串是否递增 is_increasing = True for i in range(1, num): if substr[i] < substr[i-1]: is_increasing = False break if is_increasing: wrds.append(substr) # 递归处理更短长度的子串 if num > 1: wrds.extend(recursion(s, num - 1)) # 去重后返回 return list(set(wrds)) # 测试 print(sorted(recursion('abca', 3)))
这个版本调用recursion('abca',3)会返回排序后的['a', 'ab', 'abc', 'b', 'bc', 'c'],符合预期。
内容的提问来源于stack exchange,提问作者alwayscurious

