Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何计算动态规划(记忆化)算法的大O_Java_Algorithm_Big O_Dynamic Programming - Fatal编程技术网

Java 如何计算动态规划(记忆化)算法的大O

Java 如何计算动态规划(记忆化)算法的大O,java,algorithm,big-o,dynamic-programming,Java,Algorithm,Big O,Dynamic Programming,如何计算DP算法的大O。我逐渐意识到我的算法计算方法并不总是有效的。我会使用简单的技巧来提取大O是什么。例如,如果我在评估下面算法的无记忆版本(删除缓存机制),我会查看递归方法在本例中调用自身的次数3次。然后我将这个值提高到n,给出O(3^n)。对于DP,这一点都不正确,因为递归堆栈没有那么深。我的直觉告诉我,DP解的大O是O(n^3)我们如何口头解释我们是如何得出这个答案的更重要的是,什么是一种可以用来找出类似问题大O的技术。由于是DP,我确信子问题的数量很重要我们如何计算子问题的数量。 pu

如何计算DP算法的大O。我逐渐意识到我的算法计算方法并不总是有效的。我会使用简单的技巧来提取大O是什么。例如,如果我在评估下面算法的无记忆版本(删除缓存机制),我会查看递归方法在本例中调用自身的次数3次。然后我将这个值提高到n,给出O(3^n)。对于DP,这一点都不正确,因为递归堆栈没有那么深。我的直觉告诉我,DP解的大O是O(n^3)我们如何口头解释我们是如何得出这个答案的更重要的是,什么是一种可以用来找出类似问题大O的技术。由于是DP,我确信子问题的数量很重要我们如何计算子问题的数量。

public class StairCase {
    public int getPossibleStepCombination(int n) {
        Integer[] memo = new Integer[n+1];
        return getNumOfStepCombos(n, memo);
    }

    private int getNumOfStepCombos(int n, Integer[] memo) {
        if(n < 0) return 0;
        if(n == 0) return 1;
        if(memo[n] != null) return memo[n];
        memo[n] = getNumOfStepCombos(n - 1, memo) + getNumOfStepCombos(n - 2, memo) + getNumOfStepCombos(n-3,memo);
        return memo[n];
    }
}
公共级楼梯{
公共整型getPossibleStepCombination(整型n){
整数[]备忘录=新整数[n+1];
返回getNumOfStepCombos(n,memo);
}
私有int getNumOfStepCombos(int n,整数[]备注){
如果(n<0)返回0;
如果(n==0)返回1;
如果(备注[n]!=null)返回备注[n];
memo[n]=getNumOfStepCombos(n-1,memo)+getNumOfStepCombos(n-2,memo)+getNumOfStepCombos(n-3,memo);
返回备忘录[n];
}
}

第一行
3
除了比较
int
值之外什么都不做,通过索引访问数组,查看
整数
引用是否为
null
。这些都是
O(1)
,所以唯一的问题是该方法被递归调用了多少次

这个问题很复杂,所以我经常作弊。我只是用计数器看看发生了什么。(我已经为此将您的方法设置为静态,但一般来说,您应该尽可能避免静态可变状态)

因此,看起来最终计数器值由
3n+1
给出

在一个更复杂的例子中,我可能无法识别模式,因此我将前几个数字
(例如1、4、7、10、13、16)
输入到中,通常会看到一个包含模式简单公式的页面

一旦你通过这种方式作弊来找出规则,你就可以开始理解规则为什么起作用了

以下是我如何理解
3n+1
的来源。对于
n
的每个值,您只需执行以下操作

memo[n] = getNumOfStepCombos(n - 1, memo) + getNumOfStepCombos(n - 2, memo) + getNumOfStepCombos(n-3,memo);
仅一次。这是因为我们正在记录结果,并且只有在尚未计算答案的情况下才执行这一行

因此,当我们从
n==5
开始时,我们将该行精确地运行了5次;一次用于
n==5
,一次用于
n==4
,一次用于
n==3
,一次用于
n==2
,一次用于
n==1
。这就是从自身调用方法
getNumOfStepCombos
的次数
3*5==15。该方法还从自身外部调用一次(从
getPossibleStepCombination
),因此调用总数为
3n+1

因此,这是一个
O(n)
算法


如果一个算法的行不是
O(1)
这个计数器方法不能直接使用,但是你可以经常采用这种方法。

第一个
3
行除了比较
int
值之外什么都不做,通过索引访问数组,看看
整数
引用是否为
null
。这些都是
O(1)
,所以唯一的问题是该方法被递归调用了多少次

这个问题很复杂,所以我经常作弊。我只是用计数器看看发生了什么。(我已经为此将您的方法设置为静态,但一般来说,您应该尽可能避免静态可变状态)

因此,看起来最终计数器值由
3n+1
给出

在一个更复杂的例子中,我可能无法识别模式,因此我将前几个数字
(例如1、4、7、10、13、16)
输入到中,通常会看到一个包含模式简单公式的页面

一旦你通过这种方式作弊来找出规则,你就可以开始理解规则为什么起作用了

以下是我如何理解
3n+1
的来源。对于
n
的每个值,您只需执行以下操作

memo[n] = getNumOfStepCombos(n - 1, memo) + getNumOfStepCombos(n - 2, memo) + getNumOfStepCombos(n-3,memo);
仅一次。这是因为我们正在记录结果,并且只有在尚未计算答案的情况下才执行这一行

因此,当我们从
n==5
开始时,我们将该行精确地运行了5次;一次用于
n==5
,一次用于
n==4
,一次用于
n==3
,一次用于
n==2
,一次用于
n==1
。这就是从自身调用方法
getNumOfStepCombos
的次数
3*5==15。该方法还从自身外部调用一次(从
getPossibleStepCombination
),因此调用总数为
3n+1

因此,这是一个
O(n)
算法


如果一个算法的行不是
O(1)
,这个计数器方法不能直接使用,但你可以经常调整方法。

保罗的答案在技术上没有错,但有点误导。我们应该通过函数如何响应输入大小的变化来计算大O符号。Paul对O(n)的回答使复杂性看起来是线性时间,而实际上它与表示n的位数成指数关系。例如,n=10有30次计算,m=2位。n=100有300次计算,m=3位。n=1000有约3000次计算,m=4位

我相信函数的复杂度是O(2^m),其中m是
memo[n] = getNumOfStepCombos(n - 1, memo) + getNumOfStepCombos(n - 2, memo) + getNumOfStepCombos(n-3,memo);