Java考试准备 - 递归任务

时间:2015-06-18 18:01:10

标签: java recursion

这是我的任务:

使用递归查找数组的第13个成员,其中每个成员都是最后两个成员乘以第二个成员的乘法。前两名成员分别为3名和3名。

这就是我提出的:

public class Zadatak2 {

    int array[] = {3,3,0,0,0,0,0,0,0,0,0,0,0};

    public Zadatak2(){
        find13(2);
    }

    public int find13(int index){
        if (index == 13){
            System.out.println("Member 13: " + array[index-1]);
            return 0;
        }
        else{
            array[index] = array[index-1] * array[index-2] - array[1];
            System.out.println(index + " : " + array[index]);
            return find13(index + 1);
        } 
    }
}

控制台输出,其中我在数组中看到索引:值:

2 : 6
3 : 15
4 : 87
5 : 1302
6 : 113271
7 : 147478839
8 : 1947758222
9 : 465247871
10 : 818773103
11 : -459621106
12 : 383828239
Member 13: 383828239

但我很确定我犯了错误或有更好的解决方案。任何帮助表示赞赏。

2 个答案:

答案 0 :(得分:1)

正如凯文W.在评论中所说的那样,未来,如果你想让别人审查你的代码......请使用codereview stackexchange"。但是,这里有一些建议。

首先,要记住,你遇到的问题很像计算斐波那契数列,并且可能有很多使用递归来计算该序列成员的例子。

其次,构建递归函数的方式使其仅限于用于查找序列中的第13个数字。你从序列的开始开始,一直到第13个数字,你正在做的事情基本上是一个迭代的解决问题的方法,通过微调来使它通过递归工作。

更好的方法是推广您的函数,以便您可以将序列成员编号作为参数传递,函数将通过递归计算它。执行此操作的方法是从目标成员编号开始,然后通过递归获取成员所需的成员。这允许该函数用于计算序列中的任何数字,而不仅仅是第13个数字。它还有一个额外的好处,即您的代码可以缩小并完成更多工作。

这是代码:

// index is the member number; it is 1 based e.g. index of 1 gives the first number in the sequence
int find(int index)
{
    if (index == 1 || index == 2)
        return 3;

    return (find(index - 1) * find(index - 2)) - find(2);
}

当解决递归问题时,通常使用的方法是从你想要解决的问题开始并将其分解(如上面的代码所示),而不是从子问题开始找到更大的问题(作为你的代码)示出)。

将递归应用于序列时,首先写出序列的数学定义,这就是必须从递归函数返回的内容。例如,在您的问题中,定义是

a [n] =(a [n-1] * a [n-2]) - a [2]

现在看看我写的解决方案。我返回的正是这个序列定义,只是在递归函数方面。函数开头的基本案例只是计算序列其余部分所需的初始成员。我鼓励你在纸上完成算法并与之一起玩,以确切了解正在发生的事情。

最后一点,这个算法在运行时方面是可怕的。每次调用find()时有三个递归调用,这意味着找到第13个成员的顺序为3 ^ 13,这是指数级的。指数算法是非常糟糕的算法,应该始终避免使用。

如果仔细检查递归,你可以看到,为了计算a [n],代码计算[n-1]和[n-2]。但是为了计算[n-1],计算[n-2]和[n-3],意味着a [n-2]被计算为TWICE。这个观察非常重要,因为我们只进行了一级递归。当所有应该有13个(对于13个成员)时,总共发生大约3 ^ 13个成员计算。所有这些时间执行相同的计算数百万次是一个可怕的浪费,并使指数算法如此糟糕。

那么如果我们存储了函数计算的每个成员呢?这种技术称为动态编程,是解决较大问题的方式存储子问题的答案,因此不会多次执行计算。实现动态编程的解决方案是:

// a variable that persists across function calls such as an instance field
int[] array = new int[20];    // just giving some extra memory in case you want to calculate other members
array[0] = -1;      //invalid member of the sequence since it is 1-based
array[1] = 3;
array[2] = 3;

//set the rest of the numbers to values letting you know they have not been set/found/calculated yet
for (int i = 3; i < 20; i++)
{
    array[i] = -1;
}

// index is the member number; it is 1 based e.g. index of 1 gives the first number in the sequence
int find(int index)
{
    if (array[index] != -1)   //if already calculated that member, just return it
        return array[index];

    //store the answer
    array[index] = (find(index - 1) * find(index - 2)) - find(2);
    return array[index];
}

使用此代码,您可以为任何数字调用find(),它将为您计算,而不仅仅是第13个数字。

最后,最重要的是,正如Kevin W.在评论中指出的那样,作为成员的负数存在意味着你得到的数字对于整数来说太大了。 Luka Milosevic说,第13名成员实际上是一个数字x10 ^ 90,这个数字太长了甚至不长。只要您不需要超过20个左右的精度数字,双打就可以工作,但由于答案中至少有90位数,双打不够准确。幸运的是,Java有一个名为BigInteger的类,它可以存储任意数量的数字,无论大小如何。为了获得答案,您可能必须使用它们,除非您想手动进行数学运算。 BigInteger的文档是here

答案 1 :(得分:0)

由于这是您被指派执行的任务,我只想给您一个提示。在我们的例子中,递归函数会使用较低的参数调用自身,最后以一些定义的值结束。

在我们的案例中,较低的值f(1)f(2)已定义为3

所以f(n) = f(n-1) * f(n-2) - f(2) f(1) = 3f(2) = 3

(如果我理解正确的任务)

现在你的工作就是编码并找到f(13)

有帮助吗?