
本文讲解如何仅通过递归(不新增参数、不调用辅助方法)提取字符串中由指定首尾字符包围的最内层子串,例如从 "f(f(f(x)))" 中提取 "x"。核心思路是每次定位最外层的 first 和 last,截取其内部并递归处理,直至无法再匹配。
本文讲解如何仅通过递归(不新增参数、不调用辅助方法)提取字符串中由指定首尾字符包围的最内层子串,例如从 "f(f(f(x)))" 中提取 "x"。核心思路是每次定位最外层的 first 和 last,截取其内部并递归处理,直至无法再匹配。
要实现一个纯递归、无额外参数、不依赖正则或栈结构的 theSub 方法,关键在于理解“最内层”子串的本质:它恰好被一对匹配的 first 和 last 字符直接包围,且这对字符本身不嵌套在其他同类型括号中——但题目并未要求验证配对合法性,而是约定输入保证存在有效嵌套,因此我们采用“贪心收缩”策略:每次取最左的 first 和最右的 last,截取二者之间的内容,并递归处理该子串。
这本质上是一种自外而内逐层剥壳的过程。例如对 "f(f(f(x)))" 调用 theSub(str, 'f', ')'):
- 第一层:
indexOf('f') = 0,lastIndexOf(')') = 9→ 截取str.substring(1, 9)得"f(f(x))"; - 第二层:
indexOf('f') = 0,lastIndexOf(')') = 6→ 截取"f(x)"; - 第三层:
indexOf('f') = 0,lastIndexOf(')') = 3→ 截取"x"; - 第四层:
"x"中无'f'或')'→indexOf返回-1,触发 base case,返回"x"。
对应实现如下:
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;
}
return theSub(str.substring(i + 1, j), first, last);
}
⚠️ 注意事项:
-
indexOf和lastIndexOf是 JDK 内置方法,题目允许使用(题干仅限制“不能用其他 方法”通常指禁止自定义辅助函数或非标准库逻辑,而非禁用String基础 API); - 必须检查
i >= j,避免因first出现在last右侧时导致无效子串(如"a)b"中first='b',last=')'); - 该解法返回的是最内层内容,而非所有嵌套层级;若需最外层(如
"f(f(f(x)))"返回"f(f(x))"),应改用indexOf配合substring后不再递归,但本题语境明确指向“最内层”; - 无显式循环、无状态变量、无迭代器——完全符合纯递归约束。
总结:递归不是“重复调用”,而是“将问题规模缩小后交由自身解决”。此处“缩小规模”的动作就是 substring(i+1, j),而终止条件是找不到合法边界。掌握这一“收缩→委托→收敛”范式,是驾驭递归思维的关键。










