日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

LeetCode 239:滑动窗口最大值 思考分析

發(fā)布時(shí)間:2023/12/1 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LeetCode 239:滑动窗口最大值 思考分析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

給定一個(gè)數(shù)組 nums,有一個(gè)大小為 k 的滑動(dòng)窗口從數(shù)組的最左側(cè)移動(dòng)到數(shù)組的最右側(cè)。你只可以看到在滑動(dòng)窗口內(nèi)的 k
個(gè)數(shù)字。滑動(dòng)窗口每次只向右移動(dòng)一位。

返回滑動(dòng)窗口中的最大值。

進(jìn)階:

你能在線性時(shí)間復(fù)雜度內(nèi)解決此題嗎?

示例:

輸入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3 輸出: [3,3,5,5,6,7] 解釋: 滑動(dòng)窗口的位置 最大值


[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7

提示:

1 <= nums.length <= 10^5
-10^4 <= nums[i] <= 10^4
1 <= k <= nums.length

暴力求解:超時(shí)

class Solution { public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {int maxnum=-10001;vector<int> result;int n= nums.size();//1、如果k> = nums.size, if(k>=n){for(int i=0;i<n;i++){if(nums[i]>=maxnum) maxnum=nums[i];}result.push_back(maxnum);return result;}//2、如果k<nums.sizeelse{int left=0;int right=0;for(left = 0;left<=n-k;left++){//更新左右邊界right=left+k-1;//更新最小值maxnum=-10001;for(int x=left;x<=right;x++){if(nums[x]>=maxnum) maxnum=nums[x]; }result.push_back(maxnum);}return result;}} };

優(yōu)化思路:
可以想到暴力方法肯定是有時(shí)間浪費(fèi)的,在滑窗移動(dòng)的時(shí)候,滑窗內(nèi)插入一個(gè)新值,消失了一個(gè)舊值,有k-1個(gè)值仍然保留著。
我們只需要比較一下新插入的值和舊的k-1個(gè)值中的最大值,將得到的最大值賦給結(jié)果數(shù)組就可以了。
一開始我想的是用兩個(gè)容量為2的數(shù)組,分別存放第一大的數(shù)值和它的下標(biāo),第二大的數(shù)值和它的下標(biāo),但是在推導(dǎo)的時(shí)候發(fā)現(xiàn)一個(gè)問題:
錯(cuò)誤代碼,具體疑問見代碼注釋:

class Solution { public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {int maxnum[2]={-10001,-10001}; //存儲(chǔ)當(dāng)前滑窗內(nèi)第一大和第二大的數(shù)值int index[2]={0,0}; //存儲(chǔ)當(dāng)前滑窗內(nèi)第一大和第二大的數(shù)值的下標(biāo)vector<int> result;int n= nums.size();if(k*n==0) return result;//1、如果k> = nums.size, if(k>=n){for(int i=0;i<n;i++){if(nums[i]>=maxnum[0]) maxnum[0]=nums[i];}result.push_back(maxnum[0]);return result;}//2、如果k<nums.sizeelse{int left=0;int right=0;//將前k個(gè)數(shù)進(jìn)行裝載for(int i=0;i<k;i++){//nums[i]比第一大還大,更新第一大if(nums[i]>=maxnum[0]){maxnum[0]=nums[i]; //第一大裝載完畢index[0]=i; } //第二大的范圍:大于等于舊的第二大,小于等于新的第一大,并且不能是第一大的數(shù)if(nums[i]>=maxnum[1] && nums[i]<=maxnum[0] && index[0]!=i){maxnum[1]=nums[i]; //第二大裝載完畢index[1]=i; }}left=1;//從第k+1個(gè)數(shù)開始for(right = k;right<n;right++,left++) {//如果移動(dòng)的時(shí)候?qū)⒆畲笾祾仐?/span>if(index[0]<left){//比較第二大的值和新插入的值的大小,獲取最大值//如果第二大值比新插入值大,則第二大值變?yōu)樽畲笾?#xff0c;但是新插入的值不一定是第二大值//所以我們需要構(gòu)建一個(gè)從大到小排列的雙端隊(duì)列!if(maxnum[1]>=)}result.push_back(maxnum);}return result;}} };

發(fā)現(xiàn)需要構(gòu)建一個(gè)從大到小排列的雙端隊(duì)列
1、新的數(shù)入隊(duì)列,并按照其大小排列,然后將比它小的數(shù)全部出隊(duì)列(因?yàn)槲覀冃枰氖亲畲笾?#xff0c;只要隊(duì)列中有數(shù)比新入隊(duì)列的數(shù)要小就說明它們絕對(duì)不可能是最大值,最大值最起碼也是大于等于新入隊(duì)列的數(shù))。
2、觀察隊(duì)首(數(shù)值最大)的索引值是否在[left,right]之間,如果不在就出隊(duì)列,直到隊(duì)首索引值滿足在[left,right]之間

class Solution { public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {vector<int> result;int n= nums.size();if(n==0 ||k==0) return result;if(k>=n){auto maxPosition = max_element(nums.begin(), nums.end());result.push_back(*maxPosition);return result;}//2、如果k<nums.sizeelse{int left=0;int right=0;// 雙向隊(duì)列 保存當(dāng)前窗口最大值的數(shù)組位置 保證隊(duì)列中數(shù)組位置的數(shù)值按從大到小排序deque< int> Dq;// 遍歷nums數(shù)組for(int i = 0;i < n;i++){// 保證從大到小 如果前面數(shù)小則需要依次彈出,直至滿足要求//如果隊(duì)尾的元素小于Nums[i],隊(duì)尾元素出隊(duì)列while(Dq.size() && nums[Dq.back()] <= nums[i]){Dq.pop_back();}// 將當(dāng)前數(shù)組下標(biāo)入隊(duì)列Dq.push_back(i);if(i>=k-1){// 判斷當(dāng)前隊(duì)列中隊(duì)首是否有效,如果隊(duì)首小于左邊界,則將隊(duì)首出隊(duì)列,直到隊(duì)首元素符合要求while(Dq.size() && Dq.front() <= i-k){Dq.pop_front(); }result.push_back(nums[Dq.front()]);}}return result;}} };

雖然AC了,但是效率不高,不過基本思路是符合大眾的:

不過上述的寫法仍然有些不簡潔,這里貼一下比較簡潔的寫法:
https://leetcode-cn.com/problems/sliding-window-maximum/solution/dan-diao-dui-lie-by-labuladong/
官方給出的dp思路,還得理解理解
https://leetcode-cn.com/problems/sliding-window-maximum/submissions/

class Solution { public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {int n = nums.size();vector<int> output(n-k+1,0);vector<int> left(n,0);vector<int> right(n,0);left[0]=nums[0];right[n-1]=nums[n-1];for(int i = 1;i<n;i++){if(i%k == 0) left[i]=nums[i];else left[i]=max(left[i-1],nums[i]);int j = n-i-1;if((j+1)%k == 0) right[j]=nums[j];else right[j]=max(right[j+1],nums[j]);}for(int i = 0;i < n-k+1;i++)output[i] = max(left[i+k-1],right[i]);return output;} };

為什么:兩數(shù)組一起可以提供兩個(gè)塊內(nèi)元素的全部信息。
考慮從下標(biāo) i 到下標(biāo) j的滑動(dòng)窗口。 根據(jù)定義,right[i] 是左側(cè)塊內(nèi)的最大元素, left[j] 是右側(cè)塊內(nèi)的最大元素。因此滑動(dòng)窗口中的最大元素為 max(right[i], left[j])

總結(jié)

以上是生活随笔為你收集整理的LeetCode 239:滑动窗口最大值 思考分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。