我正在解决一些练习问题,这些问题要求我给出目标时间复杂度和空间复杂度。其中一个目标时间复杂度为O(N+M)。我对O(N+M)算法的直观理解有些困难。有没有人能举个例子或清晰地解释一下?我尝试想到的每个示例似乎都像O(N*M)。
我正在解决一些练习问题,这些问题要求我给出目标时间复杂度和空间复杂度。其中一个目标时间复杂度为O(N+M)。我对O(N+M)算法的直观理解有些困难。有没有人能举个例子或清晰地解释一下?我尝试想到的每个示例似乎都像O(N*M)。
一个简单的算法示例,其时间复杂度为O(m+n)
:
int sum(int[] nArr, int[] mArr) {
int sum = 0;
for(int i : nArr) {
sum += i;
}
for(int i : mArr) {
sum += i;
}
return sum;
}
为了计算总和,您需要遍历nArr
(大小为n
)中的所有元素和mArr
(大小为m
)中的所有元素,因此总体复杂度为O(m+n)
。O
)描述了算法的性能(例如时间或空间)如何取决于输入的大小,它是“盲目”的,不针对特定的输入。当你写 O(m+n)
时,这意味着当m > n时,该算法将花费 O(m)
时间,而当m < n时,则需要 O(n)
时间。无论如何,O(m+n) = O(max(m,n))
。 - Shaked一个O(n + m)算法的快速简单示例:
for (i = 0; i < n; i++)
{
// do something but don't loop or invoke recursive functions
// only constant O(c) complexity is allowed: a simple series of commands
}
for (i = 0; i < m; i++)
{
// idem
}
当增加时,复杂度是可交换的 (O(n + m) == O(m + n)),这意味着您可以反转两个for()
而不影响复杂度。显然,在算法级别上,反转后的循环可能与直接的循环并不等价。
作为额外的帮助,这里有一个O(n * m)算法的例子:
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
// do something but don't loop or invoke recursive functions
// only constant O(c) complexity is allowed: a simple series of commands
}
}
再次强调,您可以在内部和外部循环之间反转而不影响复杂度(O(n * m) == O(m * n))。同样的显而易见的考虑也适用。
对于您可能放入for()
体中的内容的限制是因为大O符号约束了上界。如果它是一个下界(小o符号),您可以放入更复杂的内容,但它永远不能低于那个。
O(M)
,因此O(M+N)
仅为max(O(M), O(N))
,仍然是线性的。 - Mephyfor(int i=0; i < n;i++){
for(int j=0; j < m;j++){
//some_code
}
}
一个非常有启示性的例子是将两个大小为M和N的已排序数组合并成一个新的排序数组。这就是归并排序的基础,需要进行O(M+N)次比较。
您可以在任何地方找到一个例子或自己尝试实现。