一、用途:
該技術將很少出現問題的嵌套for循環轉換爲單個for循環,從而減少時間複雜度。
二、例題:
例題1:
給定一個長度爲n的數組。
求連續k個元素的和最大值sum
Input : arr[] = {100, 200, 300, 400}
k = 2
Output : 700
- 方法一:暴力嵌套
int maxSum(int arr[], int k)
{
int max_sum = INT_MIN;
for (int i = 0; i < arr.length - k + 1; i++) {
int current_sum = 0;
for (int j = 0; j < k; j++)
current_sum = current_sum + arr[i + j];
max_sum = max(current_sum, max_sum);
}
return max_sum;
}
- 方法二:我們利用滑動窗口技術將它改成一個for循環,以減少時間複雜度
1.我們使用一個窗口,窗口一共有k個窗格,第一個窗格放在數組元素的最最左邊。我們利用一個for循環算出這個窗口中數組前k個元素的和,並把值存入window_sum
2.我們線性地移動這個窗口,直到這個窗口最右邊的窗格到達數組的最右邊元素。
3.爲了得到移動 後的窗口中的元素的和,將原來窗口的第一個窗格的元素除去,並且加上當前窗口最右邊的值
public int maxSum(int arr[],int k)
{
//第一個窗口的值
int window_sum=0;
for(int i=0;i<k;i++)
window_sum=window_sum+arr[i];
//初始化最大值
int max_sum=window_sum;
for(int i=k;i<arr.length;i++)
{
//線性移動窗口,直到窗口最右邊窗格到達數組盡頭
window_sum=window_sum+arr[i]-arr[i-k];
max_sum=Math.max(max_sum,window_sum);
}
return max_sum;
}
例題2:
給定一個數組 nums,有一個大小爲 k 的滑動窗口從數組的最左側移動到數組的最右側。你只可以看到在滑動窗口 k 內的數字。滑動窗口每次只向右移動一位。
返回滑動窗口最大值。
示例:
輸入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
輸出: [3,3,5,5,6,7]
該題是LeetCode239題。
利用滑動窗口。
思路:
特殊情況:長度爲0的數組,則返回[]
一般情況:
- 1.利用一個 雙端隊列,在隊列中存儲元素在數組中的位置角標, 並且使隊列的首元素是最大值
- 2.當遍歷到一個新元素時:
如果隊列裏有比當前元素小的,就將其移除隊列;
如果隊列裏沒有比當前元素小的,就將其添加到隊列裏;
如果隊列元素位置之差大於 k,就將隊首元素移除。 - 3。將隊列中的第一個元素添加到數組ans中,返回ans
public int[] maxSlidingWindow(int[] nums,int k)
{
if(nums.length==0)
return new int[0];
int[] res = new int[nums.length - k + 1];
Deque<Integer> deque = new LinkedList<>();
for (int i = 0; i < nums.length; i++) {
while(!deque.isEmpty()&&nums[i]>nums[deque.getLast()])
deque.removeLast();
deque.add(i);
if(deque.getFirst()==i-k)
deque.removeFirst();
if(i>=k-1)
res[i-k+1]=nums[deque.getFirst()];
}
return res;
}