可以手动分割递归吗?

时间:2017-04-01 06:30:22

标签: java eclipse recursion split

我有这个工作表问题,我只是看不出它是如何手工完成的。每个方法调用另外两个方法来运行,因此每个方法都会调用另外两个方法。我不知道如何跟踪它的任何一个。我不知道除了把它放到Eclipse中之外怎么会找到答案。

static int fun(int x) {
    if(x < 1) {
        return 1;
    } else {
        return x + fun(x-1) + fun(x-2);
    }
}

public static void main(String[] args) {
    System.out.println(fun(4));
}

4 个答案:

答案 0 :(得分:0)

首先,“拆分递归”不是我之前遇到过的术语。 Google认为我正在询问如何使用递归实现split函数;例如将字符串分成单词。

如果您在询问是否可以手动执行该计算(即fun(n)计算n的某些值,那么答案显然是肯定的。你只需要一张足够大的纸和一些耐心 1

如果你问是否有可能为fun(n)提出一个“封闭形式”等式......我怀疑答案是肯定的。然而,这是一个数学问题而不是编程问题。 (基本上,你将fun的声明映射到一个递归关系......并解决它。在这种情况下,它可能需要第一年的Uni数学技能。一旦你有封闭的形式,它将很容易证明通过归纳纠正。)

如果您询问是否有更快的程序来计算fun(n),那么答案是肯定的:

  • 如果您使用了memoization,则会有一个O(N)解决方案。
  • 如果您可以派生封闭表格,则可以使用O(1)解决方案。

(我假设您可以使用intlong算术。)

1 - 实际上,对于足够大的N值,您应该能够使用铅笔和纸张(和智能)比运行该程序更快地计算fun(n)。该程序具有复杂性(2^N) ...正如所写。

答案 1 :(得分:0)

更简单的解决方案:声明一个足够大的数组,使fun(4)的值保持在您需要的值。在要求int[5]时,您需要x + 1。填写前两个元素的硬编码值,然后在循环中使用公式填充其余条目。现在你的结果在最后一个元素中。

可能的空间需求优化:通过循环的所有时间只需要最后两个和当前值,因此您无需将所有值存储在大小为['One', 'Two', 'Three'] 的数组中。

答案 2 :(得分:0)

如果您指的是有时多次调用自己的函数,那么是!

基本案例:x < 1 ==> 1fun(-1)以及fun(0)代替1

fun(1)              ; == [substitute default case with result]
1 + fun(0) + fun(-1); == [substitute base cases]
1 + 1 + 1           ; ==> 3

fun(2)              ; == [substitute default case with result]
2 + fun(1) + fun(0) ; == [substitute fun(1) with previously calculated result]
2 + 3 + fun(0)      ; == [substitute base cases]
2 + 3 + 1           ; ==> 6

fun(3)              ; == [substitute default case with result]
3 + fun(2) + fun(1) ; == [substitute with previously calculated result]
3 + 6 + 3           ; ==> 12

fun(4)              ; == [substitute default case with result]
4 + fun(3) + fun(2) ; == [substitute with previously calculated results]
4 + 12 + 6          ; ==> 22

你可以这样开始使用fun(4)

fun(4) ; == [expand default cases]
4 + 
fun(3) + 
fun(2) ; == [expand default cases]
4 + 
3 + fun(2) + fun(1) +
2 + fun(1) + fun(0) ; == [expand fun(2) default case]

4 + 
3 + (2 + fun(1) + fun(0)) + fun(1) + 
2 + fun(1) + fun(0) ; == [group]

4 + 3 + 2*2 + 3*fun(1) + 2*fun(0) ; == [expand default cases]

4 + 3 + 2*2 + 2*fun(0) +
3*(1 + fun(0) + fun(-1)) ; == [group, group x<1 as b]

4 + 3+ 2*2 + 3*1 + 8*fun(b) ; == [expand base cases]
4 + 3+ 2*2 + 3*1 + 8*1      ; == [calculate]
; ==> 22

我觉得它有点乱。特别是如果你不将几个电话组合在一起,那可能会很痛苦。

请注意,如果函数结果未直接映射到其参数,则无法执行此操作。作为一种享受,这是一个更好的功能版本:

static int fun(int n) {
    return fun(n, 0, 1, 3);
}

static int fun(int n, int v, int a, int b) {
    return n >= v ? a : fun(n, v+1, b, a+b+n+2);
}

它似乎与序列A066982一致,只是省略了第一个元素。

答案 3 :(得分:0)

所以你想要的是系列的第n个项:Un = n + U(n-1)+ U(n-2)。

由于没有人提到它,这里是使用2个累加器的尾递归版本,你想要在OCaml中做什么:

let f x =
  let rec f' acc' acc'' i =
    if i = x then i+acc''
    else f' (i+acc'') (i+acc'+acc'') (i+1)
  in f' 1 1 0

如果您正在使用尾部优化的语言(如嗡嗡声......请说OCaml),它会超级快。既然你没有,这就是Java中悲伤,不优雅,命令式的版本:

public static int f (int x){
  int acc1 = 1 ,acc2 = 1;
  for (int i = 0; i<x; i++){
    int tmp = acc1;
    acc1 = i+acc2;
    acc2 = i+tmp+acc2;
  }
  return x+acc2;
}

正如您所看到的,无需使用memoization或巨大的数组或类似的复杂事物。一个简单的for循环可以做到这一点:)。

您可以通过在循环体内打印(x + acc2)来获得所有中间结果