【问题标题】:Multiple time complexity solutions for recursive Pascal triangle algorithm?递归帕斯卡三角算法的多个时间复杂度解决方案?
【发布时间】:2017-04-05 13:35:02
【问题描述】:

我在 Java 中创建了以下简单算法,以递归方式计算帕斯卡三角形,形式为 2D 整数列表:

public class PascalTriangleRec{
    private final int[][] points;

    public PascalTriangleRec(int size){
        points = new int[size][];
        for (int i =0;i<size;i++){
            int[] row  = new int[i+1];
            for (int j = 0;j<=i;j++){
                row[j]=getValueAtPoint(i,j);
            }
            points[i]=row;
        } 
    }
    public static int getValueAtPoint(int row, int col){
        if (col == 0 || col == row) return 1;
        else return getValueAtPoint(row-1,col-1) + getValueAtPoint(row-1,col);
    }
}

我需要知道这个算法的时间复杂度。我在 StackOverflow 上找到了another question,它给出了 getValueAtPoint 函数的时间复杂度为 O(2^n/sqrt(n))。我想,由于这个函数嵌入在两个嵌套的for循环中,整个帕斯卡三角形的时间复杂度是O(sqrt(n^3)*2^n)。我很确定这个推理是正确的。

另一方面,我设计了一种完全不同的方式来思考这个问题,如下所示:

帕斯卡三角形有一个特定的性质,称为帕斯卡推论 8。这个性质表明给定行 r 上所有系数的总和等于 2^r,r 从 0 开始。

您还可以注意到,我的代码示例中的 getValueAtPoint 函数将继续递归调用自身,直到它在某个时刻返回 1。这意味着帕斯卡三角形中的所有系数都是通过将该系数的值加 1 来形成的。

由于加 1 需要一个常数时间,因此可以说计算三角形中给定行所需的时间等于某个常数时间乘以该行中所有系数的组合值。这意味着三角形中给定行 r 的时间复杂度必须为 2^r。

计算整个三角形所需的时间等于计算三角形中所有行所需时间的总和。这会产生一个几何级数,它计算所有 2^r 的总和,因为 r 从 0 到 n-1。

利用几何级数的求和属性,这个级数可以改写成下面的form

这意味着根据这个最后推导的算法的时间复杂度是O(2^n)。

这两种方法会产生不同的结果,尽管它们在我看来都是合乎逻辑且正确的。我的问题首先是这两种方法是否正确,并且是否可以同时被视为正确?我认为它们都是正确的,但第二个更准确,因为对于第一个,getValueAtPoint 函数采用最坏的情况,并应用于所有系数,这显然是实际情况并非如此。这是否意味着第一个变得不正确,即使它背后的逻辑是正确的,只是因为存在更好的方法?

【问题讨论】:

    标签: java recursion time-complexity pascals-triangle


    【解决方案1】:

    简单的答案是“变量太多”。首先,您的分析完全正确:复杂性取决于所有计算值的总和。同样的逻辑是得到 O(2^n/sqrt(n)) 的答案的基础。

    有两个问题:

    • 小问题:Stirling 的近似值就是这样:省略了一些项。我认为当你把所有的循环组合起来时它们就会掉出来,但我必须仔细研究这些令人讨厌的细节才能确定。
    • 大问题:你组合的n的值不一样n。您合并的最后一个 n 值是 i 从 0 到 size;对于 getValueAtPoint 的初始调用,i 的每个值都变为 n

    试着对你之前的复杂度从 0 到 n 求和,看看你得到了什么?

    .

    【讨论】:

    • 我想如果我理解正确的话,你的意思是第二种方法没有考虑到所有对 getValueAtPoint 的递归调用,因为对于 i=n 有很多调用并不直接return 1 但这仍然需要考虑?你的意思是我应该把嵌套的for循环想象成一阶推导的总和吗?问题是由于第一个解决方案中的 Sqrt(n),我无法找到一种方法来在数学上简化结果系列。所以如果我没记错的话,第一种方法是唯一完全正确的方法吗?
    • 是的,这就是我的意图。然而,我的“小问题”点是应用程序中的一个主要问题,现在我再看一遍:Stirling 的工作推导出使用 sqrt(n) 作为近似值的一部分;这不是直接形式。要进行总结,您还必须深入研究他的错误术语。包括那些应该扭转那个sqrt的丑陋。就个人而言,我会编写一个小程序来计算该近似值,进行求和,看看它与您的 2^n 数字有多接近。
    • 请原谅我,但我没有非常理论的背景。我不太了解斯特林近似值,只是假设我提到的另一篇文章的推导是正确的。另一方面,我可以为您提供我收集的测试数据。我使用两个近似公式绘制了结果。结果可以在这里找到:imgur.com/a/HhXCV。如您所见,2^n 方法似乎效果最好。这是否意味着我的第二种方法毕竟更好,而我忘记的额外递归调用可以忽略不计?
    • 右:额外调用的复杂度较低;我认为它是 O(n),它退出了复杂性计算。不用担心无法转换斯特林作品的总和; 不能再这样做了,我自己。我的观点是,如果您可以完成它,我希望您会发现所有这些详细的术语结合起来会得出相同的 2^n 结果。
    • 非常感谢您的宝贵时间!我想我现在已经足够了解这一点,可以继续我的项目了。您的帮助对我非常有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-23
    • 1970-01-01
    相关资源
    最近更新 更多