【问题标题】:Time complexity of the code below?下面代码的时间复杂度?
【发布时间】:2011-04-18 14:29:42
【问题描述】:

谁能告诉我以下代码的时间复杂度?

#include<iostream>
#include<string.h>
using namespace std;
int main()
{
char a[100]= "Gosh I am confused :D";
int i,count= -1,display_ToVal= strlen(a)-1, display_FromVal;

for( i=strlen(a)-1 ; i>=0 ; i=i+count)
{
        if ( (a[i] == ' ' || i == 0) && count == -1)
        {
         cout << " ";
         display_FromVal = i;
         count = 1;
         if ( i == 0 )
                cout << a[i];
         continue;
        }       

        else if( count == 1 && i == display_ToVal)
        {
         cout << a[i];
         display_ToVal = display_FromVal - 1;
         i = display_FromVal;
         count = -1;
         if(display_FromVal == 0)
                 break;
         else
                 continue;
        }

        else if (count == 1)
         cout << a[i];

        else
         continue;
}

return 1;
} 

我真的很困惑这是否可以归类为O(n)。请帮忙,提前谢谢。

【问题讨论】:

  • 如果您告诉我们是什么让您怀疑它是 O(N),我们可以帮助您更好地理解。
  • Nitpick:n 是多少,您的输入大小?如所写,代码不接受任何输入并在恒定时间内运行。 “呃,字符串长度”并不是一个完整的答案,因为看起来行为取决于字符串中的空格,这是输入的另一个参数。
  • @Cristopher:复杂性无论如何都取决于字符串的大小。我认为这里的正确问题是这里最好、平均和最差情况的时间复杂度是多少。
  • 我刚刚在这种情况下硬编码了 i/p,但 i/p 可以是任何东西。由于 I 的值是递增和递减的,所以我在是否可以将其视为 O(n) 的问题上进退两难。

标签: c++ algorithm time-complexity


【解决方案1】:

算法可以用伪代码概括为:

  1. 标记当前位置
  2. 一次后退一个字符,直到找到空格或到达输入结尾
  3. 现在继续将每个字符复制到输出,然后返回到 1.,除非达到 eoi

所以输入被反向遍历一次,然后再向前遍历一次,但在第 2 步或第 3 步中都没有回到先前读取的位置。当从第 3 步切换到 1 时,它直接调整迭代器. count 变量用于跟踪算法的状态(它实际上是一个简单的状态机)。它也被复用来定义迭代的方向。

所以,算法其实就是O(n)


为了更清楚,可以这样重写,而不改变复杂性:

void printStringWithWordReversed(const char* a) {
    int i,j,display_ToVal= strlen(a)-1, display_FromVal;
    for( i=display_ToVal; i>=0 ; i=i+-1)
    {
        if ( (a[i] == ' ' || i == 0))
        {
         // When entering this branch, we are switching from state 2 to
         // state 3 (this is the content of the first branch).
         cout << " ";
         display_FromVal = i;
         if ( i == 0 )
                cout << a[i];
         // This loop correspond to the state 3, and is equivalent to the
         // previous code in the particular case when count == 1.
         for (j = display_FromVal+1; j <= display_ToVal; j=j+1)
         {
             cout << a[j];
         }
         // This postlude correspond to the transition from state 3 to state 1
         // and correspond to the second branch in the original algorithm.
         display_ToVal = display_FromVal - 1;
         if ( i == 0 )
            break;
         continue;
        }       
    }
}

所以我们从末尾开始查找每个单词并以正确的顺序输出它们。这显然是 O(n) 的两个实现(如果我们假设 cout 的插入运算符 charO(1),则在时间和空间上),因为添加了一个 固定数字(这里是两个) O(n) 算法仍然是 O(n)(常量被忽略)。

【讨论】:

  • 第一个注意到 i 不会改变一个常数值的解决方案。 +1
  • 第一个解释且不跳入“一个循环 = O(N)”谬误的解决方案。 +1
  • 谢谢,回答重点。我很困惑这种循环变量在遍历输入时递增和递减的场景是否可以称为 O(n)。你的解释有帮助。谢谢:-)
【解决方案2】:

"{for(i=strlen(a)-1 ; i>=0 ; i=i+count)}"

您的代码中只有一个 for 循环,其索引 i 呈线性变化。 这就是为什么它的 O(n)

【讨论】:

  • “一个循环 = O(N)”的谬误。 i 没有线性变化。
  • int i =1;int n=1000;而(i
  • i 上下变化,因为 count 可以是 +1 或 -1。我投了反对票,因为对线性行为的解释很差(不存在)。一个有用的答案将有助于消除 OP 的困惑。
  • 对不起,我没有注意到我可能是-1。顺便说一句,我的解释似乎并不含糊:)
  • 从技术上讲,这个答案可能是正确的。甚至 logN 也是 O(N)。当然,单个循环完全有可能是 Omega(nlg n) 甚至。即使是 i=i+count。
猜你喜欢
  • 1970-01-01
  • 2020-07-24
  • 1970-01-01
  • 1970-01-01
  • 2018-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多