我正在研究算法 - 时间复杂度和递归。 我实际上可以解决递归问题,因为这是简单的数学运算。但代码部分是问题所在。
例如,这是我带来的问题: https://brilliant.org/practice/big-o-notation/?problem=complexityrun-time-analysis-2-2
public int P(int x , int n){
if (n == 0){
return 1;
}
if (n % 2 == 1){
int y = P(x, (n - 1) / 2);
return x * y * y;
}
else{
int y = P(x, n / 2);
return y * y;
}
}
这是一个简单的电源功能。 T(n)= O(g(n))这个函数的运行时间很大,我必须找到它。
解决方案说, “当功率为奇数时,执行额外的乘法运算。为了计算时间复杂度,让我们首先看一下最糟糕的情况,这意味着让我们假设需要一个额外的乘法运算。“
但是,我不明白下一部分,解决方案说: 递归关系是
T(n) = T(n/2) + 3, T(1)=1
1)为什么常数第3部分?
if (n % 2 == 1){
int y = P(x, (n - 1) / 2);
return x * y * y;
}
2)我实际上并不确切地知道为什么T(1)= 1。 我很困惑.. 在计算时间复杂度时我们应该考虑哪些操作?
例如,T(1)= 1部分必须与
相关if (n == 0){
return 1;
}
if (n % 2 == 1){
int y = P(x, (n - 1) / 2);
return x * y * y;
}
这一部分和我想问一下T(1)= 1是否来自if语句/ assign语句/ return语句..
之后我理解,解决了上面的递归关系,但我坚持使用递归关系本身。
请帮助我算法大师 s ..
答案 0 :(得分:1)
在计算时间复杂度时我们应该考虑哪些操作?
答案会让你失望:你算什么操作并不重要。这就是我们在分析算法和表达时间/内存要求时使用big-Oh的原因。它是一种渐近符号,描述了对于大的n值,算法会发生什么。通过Big-Oh的定义,我们可以说1 / 2n ^ 2和10n ^ 2 + 6n + 100都是O(n ^ 2),即使它们不是相同的函数。计算所有操作,只会增加一些不变因素,这就是为什么你认为哪些操作并不重要。
通过上述,常数只是O(1)。这忽略了细节,例如10和10000都是O(1)。
有人可能会争辩说,指定表达式T(n) = T(n/2) + 3
中的确切操作数不是很正确,因为没有操作定义的定义,而且相同的操作可能需要不同的时间。不同的计算机,所以准确地计算操作的数量在最好的情况下有点无意义,在最坏的情况下完全错误。更好的说法是T(n) = T(n/2) + O(1)
。
T(1)=1
表示基本情况,它以恒定时间求解(读取:每次运算的常数)。同样,更好(更正式)的说法是T(1)=O(1)
。