嵌套在while循环中的for循环的时间复杂度是多少?

时间:2017-04-07 00:12:53

标签: javascript time-complexity big-o computer-science

我正在尝试优化功能。我相信这个嵌套for循环是二次的,但我不是正面的。我重新创建了下面的功能



const bucket = [["e","f"],[],["j"],[],["p","q"]]
let totalLettersIWantBack = 4;

//I'm starting at the end of the bucket
function produceLetterArray(bucket, limit){
  let result = [];
  let countOfLettersAccumulated = 0;
  let i = bucket.length - 1;
    while(i > 0){
      if(bucket[i].length > 0){
        bucket[i].forEach( (letter) =>{
        if(countOfLettersAccumulated === totalLettersIWantBack){
          return;
        }
        result.push(letter);
       countOfLettersAccumulated++;
        })
      }
      i--;
    }
  return result;
}

console.log(produceLetterArray(bucket, totalLettersIWantBack));




4 个答案:

答案 0 :(得分:3)

这些问题的 技巧 。对于要分析其复杂性的代码,只需编写在最坏的情况下执行每个语句所需的时间,假设不存在其他语句。请注意以#operations worst case:

开头的评论

对于给定的代码:

while(i > 0){ //#operations worst case: bucket.length
  if(bucket[i].length > 0){ //#operations worst case:: 1
    bucket[i].forEach( (letter) =>{  //#operations worst case: max(len(bucket[i])) for all i
    if(countOfLettersAccumulated === totalLettersIWantBack){ //#operations worst case:1
      return;
    }
    result.push(letter); //#operations worst case:1
   countOfLettersAccumulated++; //#operations worst case:1
    })
  }
  i--; ////#operations worst case:: 1
}

我们现在可以将所有最坏情况时间乘以(因为它们都可以在最坏的情况下实现,您总是可以设置totalLettersIWantBack = 10 ^ 9 )以获得O复杂度片段:

复杂性= O(bucket.length * 1 * max(len(bucket[i])) * 1 * 1 * 1 * 1)

= O(bucket.length * max(len(bucket[i]))

如果每个桶[i]的长度是常数K,那么您的复杂性会降低到: O(K * bucket.length ) = O(bucket.length)

请注意,随着元素数量的增加,推送操作的复杂性可能不会保持不变(最终,运行时需要为添加的元素分配空间,并且可能必须移动所有现有元素)。

答案 1 :(得分:1)

这是否是二次方取决于您考虑的N和铲斗的组织方式。如果N是字母总数,那么运行时将受到存储桶中的容器数量的限制,如果大于N,或者如果N较大则运行符由存储桶中的字母数限制。在任何一种情况下,搜索时间随着较大的界限线性增加,如果一个将支配另一个,则时间复杂度为O(N)。这实际上是一个线性搜索"转"在其中,重新划分线性搜索并将其间隔开不会改变时间复杂度。一段代码中存在多个循环并不能使它成为非线性的。再次进行线性搜索示例。我们搜索一个列表,直到找到最大的元素。



//12 elements
var array = [0,1,2,3,4,5,6,7,8,9,10,11];
var rows = 3;
var cols = 4;

var largest = -1;

for(var i = 0; i < rows; ++i){

    for(var j = 0; j < cols; ++j){
        var checked = array[(i * cols) + j];
        if (checked > largest){
            largest = checked;
        }      
    } 
}
console.log("found largest number (eleven): " + largest.toString()); 
&#13;
&#13;
&#13;

尽管使用了两个循环而不是一个循环,但运行时复杂度仍为O(N),其中N是输入中元素的数量。将其向下扫描使得每个索引实际上是多个元素的数组,或者通过空区分离相关元素并不会改变运行时复杂性线性约束的事实。

答案 2 :(得分:0)

这在技术上是线性的,n是矩阵中元素总数的数量。这是因为退出条件是 bucket 的长度,并且对于 bucket 中的每个数组,您检查 countOfLettersAccumulated 是否等于 totalLettersIWantBack < / em>的。不断关注价值观。

如果您正在寻找与矩阵尺寸相匹配的答案,那会变得更加复杂,因为它看起来像 bucket 的尺寸不固定。

您可以通过在 bucket foreach之外添加额外的检查来将此位代码转换为常量,如果 countOfLettersAccumulated 等于 totalLettersIWantBack 然后你休息一下。

答案 3 :(得分:0)

我喜欢@axiom explanation的复杂性分析。

只是想添加可能的优化解决方案。

UPD .pushO(1))加快了.concatO(n^2)

这里也是测试Array push vs. concat

&#13;
&#13;
const bucket = [["e","f"],[],["j", 'm', 'b'],[],["p","q"]]
let totalLettersIWantBack = 4;

//I'm starting at the end of the bucket
function produceLetterArray(bucket, limit){
  let result = [];

  for(let i = bucket.length-1; i > 0 && result.length < totalLettersIWantBack; i--){
    //previous version
    //result = result.concat(bucket[i].slice(0, totalLettersIWantBack-result.length));
    
    //faster version of merging array
    Array.prototype.push.apply(result, bucket[i].slice(0, totalLettersIWantBack-result.length));
  }
  return result;
}

console.log(produceLetterArray(bucket, totalLettersIWantBack));
&#13;
&#13;
&#13;