Java 具有线性时间复杂度的嵌套循环? public int[]最大滑动窗口(int[]nums,int k){ int n=单位长度; 如果(n==0){ 返回nums; } int[]结果=新的int[n-k+1]; LinkedList dq=新建LinkedList(); 对于(int i=0;i=0){ 结果[i-k+1]=nums[dq.peek()]; } } 返回结果; }

Java 具有线性时间复杂度的嵌套循环? public int[]最大滑动窗口(int[]nums,int k){ int n=单位长度; 如果(n==0){ 返回nums; } int[]结果=新的int[n-k+1]; LinkedList dq=新建LinkedList(); 对于(int i=0;i=0){ 结果[i-k+1]=nums[dq.peek()]; } } 返回结果; },java,time-complexity,big-o,nested-loops,Java,Time Complexity,Big O,Nested Loops,据我所知,这段代码的最坏情况复杂性为n*k,因为在最坏情况下,内部while循环将执行k次。然而,作者说,摊销时间复杂度为O(n)。怎么样?我不完全理解?因为内部(while)循环对于外部(for)循环的每次迭代都有不同的迭代次数,所以不能简单地用k来限制该循环的迭代次数,因为这个限制不够严格 相反,我们可以尝试计算内部循环所有迭代中的操作总数 外部循环将每个索引精确地添加到队列中一次(在dq.offer(i)中) 添加到队列中的每个索引只能删除一次-通过dq.poll()或通过dq.pollL

据我所知,这段代码的最坏情况复杂性为n*k,因为在最坏情况下,内部
while
循环将执行k次。然而,作者说,摊销时间复杂度为O(n)。怎么样?我不完全理解?

因为内部(while)循环对于外部(for)循环的每次迭代都有不同的迭代次数,所以不能简单地用k来限制该循环的迭代次数,因为这个限制不够严格

相反,我们可以尝试计算内部循环所有迭代中的操作总数

外部循环将每个索引精确地添加到队列中一次(在
dq.offer(i)
中)

添加到队列中的每个索引只能删除一次-通过
dq.poll()
或通过
dq.pollLast()

由于
while
循环的每次迭代都必须从队列中删除一个元素,因此while循环的所有迭代(在外部for循环的所有迭代中)都受到
n
的限制(因为删除的次数不能超过
n
)。因此,while循环的所有迭代对总运行时间的贡献
O(n)

除了while循环之外,外部for循环中的其他操作显然需要固定的时间,因此当添加外部循环的所有迭代时,它们需要
O(n)
时间


因此,总运行时间为
O(n)

循环将执行
k次。但最终队列中只会有
n
项,因此,在所有循环中,您最多会弹出
n
次。@WillemVanOnsem知道了,但在循环时签入条件又如何呢!dq.isEmpty()&&nums[i]>=nums[dq.peekLast()]这肯定会超过n,对吗?那么,为什么我们在计算时间复杂度时只考虑dq.pollLast操作,而不考虑while循环中的条件检入呢?当然,这也会消耗时间,对吧?队列为空时,最多会有
n-1
检查,因此“无用”检查。因此,在最多
3n-2
次,我们的目标是弹出队列,因此
3n-2
,但这仍然是线性的。请注意,每次条件保持不变时,我们都会弹出队列。明白了,但在循环
时,条件签入又如何呢!dq.isEmpty()&&nums[i]>=nums[dq.peekLast()]
这肯定会超过n对吗?那么,为什么我们在计算时间复杂度时只考虑操作
dq.pollLast
,而不考虑while循环中的条件检入?当然这也要花费时间,对吗?@dev_ios999对
的评估!dq.isEmpty()&&nums[i]>=nums[dq.peekLast()]
需要固定的时间(因为
LinkedList
是一个双链接列表,所以
peekLast
使用对最后一个元素的引用)。该条件最多可以是
true
n
次(因为当一个元素为true时,我们会从队列中删除它)。它最多可以是
false
n
次,每个
i
值一次,因为当它是
false
时,我们就打破了循环。因此,该条件对总运行时间的贡献最大为O(2*n)=O(n)。
public int[] maxSlidingWindow(int[] nums, int k) {
    int n = nums.length;
    if (n == 0) {
        return nums;
    }
    int[] result = new int[n - k + 1];
    LinkedList<Integer> dq = new LinkedList<>();
    for (int i = 0; i < n; i++) {
        if (!dq.isEmpty() && dq.peek() < i - k + 1) {
            dq.poll();
        }
        while (!dq.isEmpty() && nums[i] >= nums[dq.peekLast()]) {
            dq.pollLast();
        }
        dq.offer(i);
        if (i - k + 1 >= 0) {
            result[i - k + 1] = nums[dq.peek()];
        }
    }
    return result;
}