
本文讲解如何仅通过递归(不新增参数、不调用辅助方法)提取字符串中由指定首尾字符包围的最内层子字符串,例如从 "f(f(f(x)))" 中精准提取 "x"。核心思路是每次递归收缩边界:定位最左 first 和最右 last,取其间的子串继续递归,直至无法再匹配边界字符为止。
本文讲解如何仅通过递归(不新增参数、不调用辅助方法)提取字符串中由指定首尾字符包围的最内层子字符串,例如从 `"f(f(f(x)))"` 中精准提取 `"x"`。核心思路是每次递归收缩边界:定位最左 `first` 和最右 `last`,取其间的子串继续递归,直至无法再匹配边界字符为止。
要实现一个纯递归、无额外参数、不依赖正则或栈结构的子字符串提取方法,关键在于理解递归的本质:将原问题不断简化为规模更小的同类子问题,直到达到可直接判定的终止条件。
在本题中,“被 first 和 last 包围的子串”并非指任意一层——而是最内层嵌套的结果。例如输入 "f(f(f(x)))",first = 'f', last = ')',期望结果是 "x"(即最里层 f(...) 中的 ...),而非 "f(f(x))" 或 "f(x)"。因此,每次递归应贪心地向内收缩:取最左侧 first 的下一个位置,到最右侧 last 的前一个位置之间的子串,再对该子串重复处理。
以下是符合所有约束的正确实现:
public static String theSub(String str, char first, char last) {
if (str.length() == 0) {
return str;
}
int i = str.indexOf(first);
int j = str.lastIndexOf(last);
// 若任一字符未找到,说明当前串已无有效包围结构,返回原串(或按需求可返回空串)
if (i == -1 || j == -1 || i >= j) {
return str;
}
// 递归处理:截取 first 后、last 前的子串
return theSub(str.substring(i + 1, j), first, last);
}关键点解析:
-
indexOf(first)总是获取最左侧匹配位置,lastIndexOf(last)获取最右侧匹配位置,二者共同框定当前最外层包围范围; -
substring(i + 1, j)自动跳过外层first和last,使下一次递归聚焦于内部内容; - 终止条件
i == -1 || j == -1 || i >= j不仅处理空串,还防止first出现在last右侧(如"a)b")导致无效截取; - 无需显式“找配对括号”,因为递归天然模拟了“剥洋葱”过程:每层只关心当前最宽泛的一组边界,层层深入即得最内核。
注意事项:
- 该方法假设
first和last是单字符,且目标结构是严格嵌套的(如括号、引号等); - 若输入中不存在合法嵌套(如
"abc"或"(x"),将直接返回原字符串——可根据需求改为返回""或抛出异常; - 时间复杂度为 O(n²)(每次
indexOf/lastIndexOf为 O(n),最多递归 O(n) 层),但满足题目对“仅递归”的硬性限制。
通过这种“定位→截断→递归”的三步模式,你不仅能解决本题,更能建立起对递归收缩边界的直觉:每一次递归调用,都是对问题空间的一次安全压缩。

















