带记忆化的递归函数时间复杂度分析:该推理是否正确?
关于字符串缩减方式数算法的时间复杂度推理正确性分析
首先先把问题背景和代码片段理清楚:
以下代码用于计算将字符串
s1缩减为字符串t的方式数。设s1长度为n,t长度为m。无记忆化时最坏时间复杂度为O(n^m);若对s1的子串递归子问题进行记忆化,时间复杂度为O(m*n),理由是每个n对应m次递归。请问该推理是否正确?代码片段如下:
static int distinctSeq(String s1, String t) { if (s1.length() == t.length()) { if (s1.equals(t)) return 1; else return 0; } int count = 0; for (int i = 0; i < s1.length(); i++) { // 原代码未写完,基于这类问题的常规逻辑,此处应该是当s1[i]匹配t的当前首字符时, // 递归调用distinctSeq(s1.substring(i+1), t.substring(1))并累加结果 } return count; }
咱们一步步分析这个推理的正确性:
1. 无记忆化时的时间复杂度推理
这个部分的结论是正确的。
在没有记忆化的情况下,最坏场景比如s1全是和t相同的字符(例如s1="aaaaa",t="aaa"):每一步匹配t的一个字符时,都有n - k种选择(k是已经匹配的t的字符数),每一次选择都会触发新的递归分支。累计下来,递归的总分支数是指数级的,粗略可以用O(n^m)来表示——因为对于t的m个字符,每一步都最多有O(n)种选择路径,最终的时间复杂度确实是O(n^m)。
2. 记忆化后的时间复杂度推理
结论是正确的,不过原理由可以表述得更精准一些。
当我们加入记忆化时,递归的子问题可以用两个参数唯一标识:i(s1当前处理的起始索引)和j(t当前处理的起始索引)。那么所有可能的子问题数量是(n+1)*(m+1),也就是O(n*m)级别的——因为i的取值范围是0到n,j的取值范围是0到m。
每个子问题只会被计算一次,之后再遇到相同的子问题直接返回记忆化的结果,不需要重复递归。所以总的时间复杂度就是子问题的总数,也就是O(n*m)。原理由里“每个n对应m次递归”的说法有点模糊,但核心结论是对的。
总结一下:你给出的两段时间复杂度推理,结论都是正确的,记忆化部分的理由可以补充得更准确,但整体判断没问题。
内容的提问来源于stack exchange,提问作者user_1357




