嵌套的while循环如何成为O(n)?

时间:2020-04-21 16:20:14

标签: javascript big-o nested-loops

我在网站www.interviewcake.com上有此代码,该网站称该代码为O(n),并且在面试蛋糕上要求团队成员进行澄清后,他们确认这是正确的。这是代码:

function reverseWords(message) {

  // First we reverse all the characters in the entire message
  reverseCharacters(message, 0, message.length - 1);
  // This gives us the right word order
  // but with each word backward

  // Now we'll make the words forward again
  // by reversing each word's characters

  // We hold the index of the *start* of the current word
  // as we look for the *end* of the current word
  let currentWordStartIndex = 0;
  for (let i = 0; i <= message.length; i++) {

    // Found the end of the current word!
    if (i === message.length || message[i] === ' ') {

      // If we haven't exhausted the string our
      // next word's start is one character ahead
      reverseCharacters(message, currentWordStartIndex, i - 1);
      currentWordStartIndex = i + 1;
    }
  }
}

function reverseCharacters(message, leftIndex, rightIndex) {

  // Walk towards the middle, from both sides
  while (leftIndex < rightIndex) {

    // Swap the left char and right char
    const temp = message[leftIndex];
    message[leftIndex] = message[rightIndex];
    message[rightIndex] = temp;
    leftIndex++;
    rightIndex--;
  }
}

面试蛋糕上的团队成员说:

*是的,有一个嵌套循环,看起来像是O(n ^ 2)。

但是,在问题过程中,我们可以看到我们没有在每个内部循环中反转O(n)个字符……我们仅将每个字符精确地反转了两次。因此,总成本最终为O(n)。

这是一个棘手的问题,因为您必须查看整个算法中所有对reverseCharacters的调用的开销,而不是每个调用本身的开销。*

不过,我仍然感到困惑,因为我们仍在内部循环中循环遍历EACH字符,并且字符串越大,则运行调用所花费的时间就越长。

我想将其开放给其他渠道,以查看是否可以对此获得更多了解,以及为什么使用O(n)而不是O(n)^ 2。

要完全清楚,我想解释一下为什么上面提供的代码中的reverseWords函数是O(n)而不是O(n)^ 2

2 个答案:

答案 0 :(得分:3)

根据我在该代码中看到的内容,外循环的工作是查找每个单词的结尾。一旦找到(并且只有这样),将调用reverseCharacters()来反转该单词中的字符。因此,两个任务中的大O相加(O(n)+ O(n)= O(2n),但仍视为O(n)),而不是相乘(O(n)* O (n)= O(n ^ 2)),就像您通常希望它们在嵌套循环中那样。

答案 1 :(得分:0)

这确实是O(n)

造成混淆的原因是在内部循环中调用了reverseCharacters()。但是,请注意何时调用。

让我们看一下字符串中的任意字符,看看它多久被“触摸”了。 让我们的角色在i的索引上i

内循环中的

reverseCharacters()在输入字符串中的每个单词被调用一次。字符i仅出现在一个单词中。

这意味着该代码的实际复杂度为:

T(n) = O(n       //    First reverseCharacters()
         +  n    // looping through all characters
         + l1    // reverseCharacters() on the first word
         + l2    // reverseCharacters() on the second word
         + ...   // and so on ...
         + lk)   // reverseCharacters() on the k'th (and last) word.

l1 + l2 + ... + lk <= n起,这意味着我们拥有:

T(n) = O(n + n + l1 + l2 + ... + lk) <= O(n + n + n) = O(n)