请考虑C
中的以下代码:
int i = 1;
while(i < n)
{
if((n – i) % 2)
i *= 3;
else
i *= 2;
}
它是更大代码的一部分。我正在尝试计算此代码的时间复杂度。我应该如何数学地处理它?我知道如何计算线性循环,但是每当我不得不面对一个非线性循环(代码中的跳转)时,就会遇到麻烦。
答案 0 :(得分:1)
好吧,如果您正在寻找时间复杂性,则可以只针对不同的值模拟算法。
在您的情况下: 假设n为奇数。 然后在第一次迭代中,我将翻倍。但是,下次(n-i)将是奇数,并且无论您乘以i多少,它都将永远不会改变(我将永远是偶数,因此(n-i)将是奇数)。因此,每次下一次迭代我都将乘以3。您可以说,在这种情况下,您的算法具有O(log3 n)时间复杂度。
如果n是偶数怎么办? 然后在第一个交互中,我将增加三倍。我们可以很容易地看到,要使(n-i)为偶数,我必须为偶数。而且它永远不会达到偶数,因为您永远不会将其乘以2。时间复杂度也是O(log3 n)
无论如何,此算法的时间复杂度为O(log3n)。如果根据输入存在多种可能的时间复杂度,则必须精确计算实际要计算的时间复杂度。通常,这是最坏的时间复杂度,因此您要尽可能地降低复杂度。
编辑:很少有澄清: 1)为什么我要检查n是偶数还是奇数?在您的算法中,改变您的算法工作方式的是以下代码:“ if((n-i)%2)”它检查(n-i)是偶数还是奇数。您不能为i取其他值,因为它在开始时设置为1。因此,我只能检查的变量是n。我不在乎n到底是多少,我只需要知道((n-i)%2)的结果是什么,所以我需要知道n是否可以被2整除。
2)如果我每次都乘以3,为什么复杂度为O(log3n)? 每次您的循环激活,我就会乘以3。因此,在执行100步后,我将乘以3 ^ 100。当i大于或等于n时,循环结束,而当1 * 3 ^ x> = n时,循环将结束。 3 ^ x> = n x> = log3(n)。
答案 1 :(得分:1)
在最坏的情况下,它可能是log3(n)
,在最糟的情况下,它可能是log2(n)
。
不过,基数的变化将是一个常数。之所以为 O(lg n),是因为该常量无关紧要,我们知道它位于这两种情况之间。 >