我在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)
。恕我直言,i
和left
都会增加,导致在最坏的情况下访问nums
的每个元素两次 - 一次是归纳变量i
然后是{{1} }}。
那么时间复杂度left
怎么样?
答案 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)
提供了更好的界限。