1. 递归优化实战:从暴力解法到高效实现
第一次看到这个题目时,我的直觉反应是"这不就是个简单的递归函数实现吗?"于是毫不犹豫地写下了最直接的递归解法。这个解法确实正确,但当我提交后看到超时的结果时,才意识到问题的严重性。
让我们先看看这个递归函数的定义:
- 当x、y、z任一小于等于0时,返回1
- 当任一参数大于20时,返回w(20,20,20)
- 当x<y<z时,返回w(x,y,z-1)+w(x,y-1,z-1)-w(x,y-1,z)
- 当x=y=z时,返回w(x-1,y,z)+2*w(x-1,y-1,z)-w(x-1,y-1,z-1)
- 其他情况返回w(x-1,y,z)+w(x-1,y-1,z)+w(x-1,y,z-1)-w(x-1,y-1,z-1)
这个看似简单的递归实现,时间复杂度却高达O(4ⁿ)。当参数为20时,会产生约1.1×10¹²次函数调用!这显然无法在合理时间内完成计算。
关键教训:递归解法的时间复杂度分析至关重要,不能仅看代码表面是否简单。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 记忆化优化:空间换时间的艺术
2.1 记忆化标记的基本原理
记忆化(Memoization)是一种优化技术,通过存储函数调用的结果来避免重复计算。对于纯函数(相同的输入总是产生相同的输出),这种方法特别有效。
具体到这个题目,我们可以:
- 创建一个三维数组memory[21][21][21]存储计算结果
- 创建一个三维布尔数组calculate[21][21][21]标记是否已计算
- 在每次计算前检查是否已计算过,若已计算则直接返回存储的结果
这种方法的本质是用空间换时间,将时间复杂度从指数级降低到多项式级别。
2.2 Java实现细节
在Java中实现记忆化需要注意几个关键点:
- 数组大小设定为21×21×21,因为参数超过20时会被截断到20
- 使用long类型存储结果,避免整数溢出
- 初始化时将所有calculate元素设为false
- 在递归函数开始时先检查记忆数组
java复制private static long[][][] memory = new long[21][21][21];
private static boolean[][][] calculated = new boolean[
