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

歡迎訪問(wèn) 生活随笔!

生活随笔

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

编程问答

每天一道LeetCode-----计算给定序列中所有长度为k的滑动窗的最大值集合

發(fā)布時(shí)間:2024/4/19 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 每天一道LeetCode-----计算给定序列中所有长度为k的滑动窗的最大值集合 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

原題鏈接Sliding Window Maximum

給定一個(gè)數(shù)組,從左到右每k個(gè)位置算作一個(gè)滑動(dòng)窗,每到達(dá)一個(gè)滑動(dòng)窗,都需要找到這個(gè)滑動(dòng)窗中最大的元素并記錄下來(lái),最后返回所有最大元素組成的數(shù)組。要求時(shí)間復(fù)雜度在O(n)

首先,如果每到達(dá)一個(gè)滑動(dòng)窗都計(jì)算一遍這個(gè)滑動(dòng)窗覆蓋的區(qū)域的最大值,那么復(fù)雜度應(yīng)該是….額…O(n*k - k*k)?k是滑動(dòng)窗大小,n是數(shù)組元素個(gè)數(shù)


有沒(méi)有什么方法可以不用每次都計(jì)算一遍最大值呢

對(duì)于滑動(dòng)窗而言,首先想到的就是向右移動(dòng)的過(guò)程中是進(jìn)行”左邊減,右邊加”的操作,即從滑動(dòng)窗中刪除離開(kāi)窗口的元素,并增加進(jìn)去窗口的元素

利用這個(gè)特性,假設(shè)已經(jīng)知道第一個(gè)滑動(dòng)窗nums[0 : k - 1]中的最大值N,那么在向右移動(dòng)時(shí),刪掉nums[0],增加nums[k],然后將N和nums[k]的較大者作為第二個(gè)滑動(dòng)窗的最大值

一切看起來(lái)非常完美,但是一旦N是nums[0],上面的想法突然變得,唔…,不太完善

不過(guò)現(xiàn)在任務(wù)倒是明朗不少,既然最大值N從窗口中離開(kāi),那么就需要知道在第一個(gè)滑動(dòng)窗中第二大元素的值,拿它和nums[k]的較大者作為第二個(gè)滑動(dòng)窗的最大值

問(wèn)題是該怎么記,同時(shí)還要保證復(fù)雜度盡量低


假設(shè)…假設(shè),有這么一個(gè)容器D,它記錄的是某些元素的下標(biāo),同時(shí)這個(gè)容器保證在這些下標(biāo)上的元素的大小順序是遞減的,也就是nums[D[0]] > nums[D[1]] > nums[D[2]] ….

另外,對(duì)于這個(gè)容器,規(guī)定

  • 可以獲得第0的元素,即有成員函數(shù)D.front()
  • 可以獲得最后一個(gè)元素,即有成員函數(shù)D.back()
  • 可以彈出第一個(gè)元素,即有成員函數(shù)D.pop_front()
  • 可以彈出最后一個(gè)元素,即有成員函數(shù)D.pop_back()
  • 可以插入一個(gè)元素到末尾,即有成員函數(shù)D.push_back()

而對(duì)于這個(gè)容易的操作,規(guī)定

  • 插入的是元素下標(biāo)而非元素的值
  • 插入元素下標(biāo)到末尾時(shí),從容器末尾開(kāi)始依次彈出指向的元素值小于要插入下標(biāo)代表的元素值的那些下標(biāo)

最后一個(gè)規(guī)定多少有些繞口,用數(shù)字表示可能會(huì)清楚些,假設(shè)某一時(shí)刻容器D中的元素為

I1, I2, I3, I4, I5

注意根據(jù)上面的規(guī)定,可以知道nums[I1] > nums[I2] > nums[I3] > nums[I4] > nums[I5]

此時(shí)遍歷到一個(gè)元素M,它的下標(biāo)為Im,那么如果要將Im插入D中時(shí),需要從D的末尾開(kāi)始,找到第一個(gè)下標(biāo)Ii滿足nums[Ii] > M,至于Ii+1, …, I5就都pop掉,然后將Im追加到D的末尾。

假設(shè)I3是第一個(gè)滿足上面要求的值,那么插入Im后,D中元素為I1, I2, I3, Im。

I4和I5在向前找nums[Ii] > M的過(guò)程中已經(jīng)被pop掉了


先提結(jié)論吧,根據(jù)上述規(guī)則,D中的下標(biāo)分別是當(dāng)前滑動(dòng)窗第一大的元素,第二大的元素,…第n大的元素的下標(biāo)。nums[D.front()]就是當(dāng)前滑動(dòng)窗覆蓋區(qū)域中的最大值

為什么是記錄下標(biāo)而不是記錄元素的值,因?yàn)橥ㄟ^(guò)記錄下標(biāo),可以判斷上一個(gè)滑動(dòng)窗的最大值是否已經(jīng)被移出了

假設(shè)某一時(shí)刻的滑動(dòng)窗位于nums[i-k+1, i-k+2, …, i-2, i-1, i],此時(shí)nums[i-k+1]是這個(gè)滑動(dòng)窗的最大值,同時(shí)也知道D.front() == i-k+1。

那么當(dāng)向右移動(dòng)一步時(shí),滑動(dòng)窗變?yōu)閚ums[i-k+2, i-k+3, …, i-1, i, i+1]

要怎么才可以知道上一個(gè)滑動(dòng)窗的最大值已經(jīng)被移出了呢,通過(guò)(i+1) - D.front() == k啦:)

此時(shí)就可以把D.front()彈出,通過(guò)調(diào)用D.pop_front()。隨后把滑動(dòng)窗新加進(jìn)來(lái)的元素nums[i+1]追加到D中,追加之后,D.front()是當(dāng)前滑動(dòng)窗的最大值所在的位置

那么有沒(méi)有上面這樣的容器呢,沒(méi)有,唔…我是說(shuō)C++標(biāo)準(zhǔn)庫(kù)里沒(méi)有,但是有個(gè)容器,它有所有容器D需要的成員函數(shù),啊終于輪到deque出場(chǎng)了(一直以為它只是作為幕后工作者的身份用來(lái)實(shí)現(xiàn)stack, queue,沒(méi)想到還有這樣的用處)

deque,俗話叫雙端隊(duì)列,在隊(duì)列的兩端都可以進(jìn)行插入刪除操作,并且復(fù)雜度是O(1)。不過(guò)對(duì)于上面的插入操作規(guī)則,需要手動(dòng)去實(shí)現(xiàn)

實(shí)現(xiàn)完叫什么,單調(diào)隊(duì)列:)

代碼如下

class Solution { public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {vector<int> res;deque<int> dq;for(int i = 0; i < nums.size(); ++i){/* 上一個(gè)滑動(dòng)窗的最大值被移出了,從容器中刪掉 */if(!dq.empty() && i - dq.front() == k)dq.pop_front();/* 將容器末尾的所有指向的元素值小于當(dāng)前值的下標(biāo)都刪掉 */while(!dq.empty() && nums[dq.back()] < nums[i])dq.pop_back();/* 將剛遍歷到的元素下標(biāo)放進(jìn)容器中 */dq.push_back(i);/* dq.front()是當(dāng)前滑動(dòng)窗第一大的元素的下標(biāo) *//* i >= k-1時(shí)才到達(dá)第一個(gè)滑動(dòng)窗 */if(i >= k - 1)res.push_back(nums[dq.front()]);}return res;} };

本題主要利用deque實(shí)現(xiàn)單調(diào)隊(duì)列,不容易理解的地方在為什么可以在插入一個(gè)下標(biāo)時(shí)可以將其他指向值小于當(dāng)前值的下標(biāo)都pop掉

考慮上面的D容器,容器內(nèi)部情況為I1, I2, I3, I4, I5

這5個(gè)值表示當(dāng)前滑動(dòng)窗的第一大的元素是nums[I1],第二大的元素是nums[I2],…, 第五大的元素是nums[I5]

同時(shí),當(dāng)前的滑動(dòng)窗為nums[I1, I2, I3, …, I5],假設(shè)右移一次后滑動(dòng)窗為nums[I2, I3, …, I5, I],根據(jù)D可知右移前滑動(dòng)窗的最大值nums[I1]已經(jīng)被移走,第二大的元素是nums[I2],此時(shí)D的情況為

I2, I3, I4, I5

假設(shè)nums[I] > nums[I2],根據(jù)上述規(guī)則,更新后的D為

I

沒(méi)錯(cuò)只有I一個(gè),因?yàn)槠渌南聵?biāo)代表的值都小于nums[I],都被pop掉了。

為什么可以只有I一個(gè)呢,因?yàn)镮的位置是當(dāng)前滑動(dòng)窗最右邊的位置,只有右移k次后才會(huì)被移走,而在右移1, 2, …, k - 1時(shí),都可以知道前k個(gè)滑動(dòng)窗的最大值

總結(jié)

以上是生活随笔為你收集整理的每天一道LeetCode-----计算给定序列中所有长度为k的滑动窗的最大值集合的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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