时间复杂度O(n)如何而不是O(n ^ 2)?

时间:2018-03-11 01:26:21

标签: c++ algorithm time-complexity

我在LeetCode.com上解决了一个问题:

  

给定正整数的向量nums,计算并打印子阵列中所有元素的乘积小于k的(连续)子阵列的数量。

代码(我用大量的在线帮助写的)如下:

class Solution {
public:
    int numSubarrayProductLessThanK(vector<int>& nums, int k) {
        if(nums.empty() || k<=1) return 0;

        int counter=0, left=0, currProd=1;
        for(int i=0; i<nums.size(); i++) {
            currProd*=nums[i];
            while(left<nums.size() && currProd>=k)
                currProd/=nums[left++];
            counter+=i-left+1;
        }

        return counter;
    }
};

虽然我了解发生了什么,但我无法理解时间复杂性如何被称为O(n)而不是O(n^2)。恕我直言,ileft都会增加,导致在最坏的情况下访问nums的每个元素两次 - 一次是归纳变量i然后是{{1} }}。

那么时间复杂度left怎么样?

2 个答案:

答案 0 :(得分:4)

虽然代码可能看起来像O(N^2) - 但是,需要注意的关键是:

  

在for循环中,left永远不会重置为0,并且总是在while循环中递增。

这意味着while循环在整个执行代码期间最多只能执行N次。因此,代码只在数组中运行两次,因此O(N)

答案 1 :(得分:1)

每次执行内循环的主体时,left都会增加1. left最初为0且永远不会超过nums.size()。因此,内循环的主体最多执行nums.size()次。

外环的主体执行正好nums.size()次。

因此函数的执行时间最多为T0 + nums.size() * T1 + nums.size() * T2,其中T0是在外循环外执行代码所需的时间,T1是执行外循环的一次迭代所需的时间内循环,T2是执行内循环的一次迭代所花费的时间。此上限的格式为A + nums.size() * B,其中A和B是一些常量。因此,函数的执行时间为O(nums.size())

当你有两个嵌套循环时,整个程序的复杂性最多是 M*N,其中M是外循环的迭代次数{{1是内循环的最大迭代次数。因此,程序的复杂性满足N。有时可以找到下限,因为内循环的迭代次数会有所不同。这里有一个不变量,保证内循环最多执行一定次数 total ,这比O(M*N)提供了更好的界限。