我如何在 Java 中找到递归方法的时间复杂度?
How would I find the time-complexity of a recursive method in Java?
我还没有完全掌握复杂性的概念,我想知道如何在这段代码中为方法 f(n) 计算它:
import java.util.Random;
public class Main {
public static void main(String[] args) {
Random r = new Random();
r.setSeed(System.currentTimeMillis());
int n = r.nextInt(20) + 1;
f(n);
}
private static void f(int n){
if(n > 0){
g(n);
System.out.println();
f(n-1);
}
}
private static void g(int n){
if(n > 0){
System.out.print('X');
g(n-1);
}
}
}
我知道这是一种递归方法,这让我很困惑。我看到每次调用函数 f() 时,都会调用 g(),并且 运行 n 次,然后 f() 再次调用自身为 n-1,直到 n=0。我不知道从哪里开始任何帮助都会很棒。谢谢。
确定递归函数运行时间的常用技术是写出递归关系,将运行时间描述为根据自身定义的量。让我们从 g 开始。如果我们让 cn 表示 g(n) 的运行时间,那么我们有
- c0 = 1(调用 g(0) 需要一定的工作量)
- cn+1 = cn + 1(调用 g(n) 做自己的工作量恒定,然后调用 g(n-1)
我们可以查看 c 的几个值,看看是否发现了一种模式:
- c0 = 1
- c1 = c0 + 1 = 1 + 1 = 2
- c2 = c1 + 1 = 2 + 1 = 3
- c3 = c2 + 1 = 3 + 1 = 4
一般来说,它看起来像 cn = n + 1。如果您愿意,可以使用归纳法证明将其形式化,但现在我们会相信它。这意味着 g 的运行时间是 O(n).
现在,让 dn 为调用 f(n) 的运行时间。注意
- d0 = 1(调用 f(0) 做恒定量的工作)
- dn+1 = dn + cn+1 (调用 f (n+1)调用g(n+1),要求cn+1起作用,然后调用f(n)
我们可以将其展开以查看是否发现了规律。
- d0 = 1
- d1 = c1 + d0 = 2 + 1
- d2 = c2 + d1 = 3 + 2 + 1
- d3 = c3 + d2 = 4 + 3 + 2 + 1
通常,它看起来像 dn = n + (n-1) + (n-2) + ... + 1。如果你想。这是一个著名的求和,它的计算结果为 n(n+1) / 2。这个数量恰好是 Θ(n2),所以总运行时间是 Θ(n2).
首先,计算 g() 被调用的次数,作为传递给 f() 的初始参数 n 的函数。这为您提供了该函数所花费的时间,是执行 g() 所花费时间的倍数,不包括递归。
然后舍弃系数和低阶项。例如,如果您的结果是 0.5n^2 + 0.5n,您将删除 0.5n,因为它是低阶项 - 不是平方 - 留下 0.5n^2,并且您将删除 0.5 系数,留下 n^2 .这意味着该函数在 O(n^2) 时间内运行。
虽然不是分析递归的一般策略,但您的 f(n)
本质上是一个循环 运行ning g(k)
,用于 k
的值跨越 1 到 n。所以 f(n)
的 运行 次本质上是 g(n)
, g(n-1)
, ..., g(2)
的 运行 次的总和, g(1)
.
由于您已经知道 g(k)
的 运行 时间本质上是 k
,因此您最终的 运行 时间是从 1 到 n 的总和。如果你知道你的求和公式,你就会知道它的顺序是 O(n2).
我还没有完全掌握复杂性的概念,我想知道如何在这段代码中为方法 f(n) 计算它:
import java.util.Random;
public class Main {
public static void main(String[] args) {
Random r = new Random();
r.setSeed(System.currentTimeMillis());
int n = r.nextInt(20) + 1;
f(n);
}
private static void f(int n){
if(n > 0){
g(n);
System.out.println();
f(n-1);
}
}
private static void g(int n){
if(n > 0){
System.out.print('X');
g(n-1);
}
}
}
我知道这是一种递归方法,这让我很困惑。我看到每次调用函数 f() 时,都会调用 g(),并且 运行 n 次,然后 f() 再次调用自身为 n-1,直到 n=0。我不知道从哪里开始任何帮助都会很棒。谢谢。
确定递归函数运行时间的常用技术是写出递归关系,将运行时间描述为根据自身定义的量。让我们从 g 开始。如果我们让 cn 表示 g(n) 的运行时间,那么我们有
- c0 = 1(调用 g(0) 需要一定的工作量)
- cn+1 = cn + 1(调用 g(n) 做自己的工作量恒定,然后调用 g(n-1)
我们可以查看 c 的几个值,看看是否发现了一种模式:
- c0 = 1
- c1 = c0 + 1 = 1 + 1 = 2
- c2 = c1 + 1 = 2 + 1 = 3
- c3 = c2 + 1 = 3 + 1 = 4
一般来说,它看起来像 cn = n + 1。如果您愿意,可以使用归纳法证明将其形式化,但现在我们会相信它。这意味着 g 的运行时间是 O(n).
现在,让 dn 为调用 f(n) 的运行时间。注意
- d0 = 1(调用 f(0) 做恒定量的工作)
- dn+1 = dn + cn+1 (调用 f (n+1)调用g(n+1),要求cn+1起作用,然后调用f(n)
我们可以将其展开以查看是否发现了规律。
- d0 = 1
- d1 = c1 + d0 = 2 + 1
- d2 = c2 + d1 = 3 + 2 + 1
- d3 = c3 + d2 = 4 + 3 + 2 + 1
通常,它看起来像 dn = n + (n-1) + (n-2) + ... + 1。如果你想。这是一个著名的求和,它的计算结果为 n(n+1) / 2。这个数量恰好是 Θ(n2),所以总运行时间是 Θ(n2).
首先,计算 g() 被调用的次数,作为传递给 f() 的初始参数 n 的函数。这为您提供了该函数所花费的时间,是执行 g() 所花费时间的倍数,不包括递归。
然后舍弃系数和低阶项。例如,如果您的结果是 0.5n^2 + 0.5n,您将删除 0.5n,因为它是低阶项 - 不是平方 - 留下 0.5n^2,并且您将删除 0.5 系数,留下 n^2 .这意味着该函数在 O(n^2) 时间内运行。
虽然不是分析递归的一般策略,但您的 f(n)
本质上是一个循环 运行ning g(k)
,用于 k
的值跨越 1 到 n。所以 f(n)
的 运行 次本质上是 g(n)
, g(n-1)
, ..., g(2)
的 运行 次的总和, g(1)
.
由于您已经知道 g(k)
的 运行 时间本质上是 k
,因此您最终的 运行 时间是从 1 到 n 的总和。如果你知道你的求和公式,你就会知道它的顺序是 O(n2).