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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

滑动窗口—中值问题

發布時間:2024/4/15 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 滑动窗口—中值问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目一:295. 數據流的中位數

問題描述

中位數是有序列表中間的數。如果列表長度是偶數,中位數則是中間兩個數的平均值。例如,[2,3,4]?的中位數是 3、[2,3] 的中位數是 (2 + 3) / 2 = 2.5。設計一個支持以下兩種操作的數據結構:

  • void addNum(int num) - 從數據流中添加一個整數到數據結構中。
  • double findMedian() - 返回目前所有元素的中位數。

示例:

  • addNum(1)
  • addNum(2)
  • findMedian() -> 1.5
  • addNum(3)?
  • findMedian() -> 2

進階:

  • 如果數據流中所有整數都在 0 到 100 范圍內,你將如何優化你的算法?
  • 如果數據流中 99% 的整數都在 0 到 100 范圍內,你將如何優化你的算法?

算法思路

由于奇數長度和偶數長度的中位數定義不同,判斷「從數據流中讀出的數的個數的奇偶性」很重要,這是因為長度的奇偶性決定了中位數的個數。當從數據流中讀出的數的個數為奇數的時候,中位數只有 1 個;當從數據流中讀出的數的個數為偶數的時候,中位數有 2 個。我們不妨分別稱它們為「左中位數」和「右中位數」。

如果數據流中每讀出 1?個數后都排一次序,「中位數」就位于這些數的「中間」。「中位數」把它們分為兩個部分,一部分是「前有序數組」,另一部分是「后有序數組」。我們發現如下事實:

  • 當從數據流中讀出的數的個數為奇數的時候,中位數是「前有序數組」中的最大值,如下左圖所示;
  • 當從數據流中讀出的數的個數為偶數的時候,左中位數是「前有序數組」中的最大值,右中位數是「后有序數組」中的最小值,如下右圖所示。

由于我們只關心這兩個 有序數組 中的最值,有一個數據結構可以幫助我們快速找到這個最值,這就是 優先隊列 。具體來說:

  • 前有序數組由于只關注最大值,可以 動態地 放置在一個最大堆中;
  • 后有序數組由于只關注最小值,可以 動態地 放置在一個最小堆中。
  • 當從數據流中讀出的數的個數為偶數的時候,我們想辦法讓兩個堆中的元素個數相等,兩個堆頂元素的平均值就是所求的中位數(如下左圖);
  • 當從數據流中讀出的數的個數為奇數的時候,我們想辦法讓最大堆的元素個數永遠比最小堆的元素個數多 11 個,那么最大堆的堆頂元素就是所求的中位數(如下右圖)。

為了得到所求的中位數,在任何時刻,兩個堆應該始終保持的性質如下:

  • 最大堆的堆頂元素,小于或者等于最小堆的堆頂元素;
  • 最大堆的元素個數或者與最小堆的元素個數相等,或者多 11 。

具體可以進行如下操作:

  • 情況 1: 當兩個堆的元素個數之和為偶數(例如一開始的時候),為了讓最大堆中多 1 個元素,采用這樣的流程:「最大堆 → 最小堆 → 最大堆」;
  • 情況 2: 當兩個堆的元素個數之和為奇數,此時最小堆必須多 11 個元素,這樣最大堆和最小堆的元素個數才相等,采用這樣的流程:「最大堆 → 最小堆」 即可。

因此無論兩個堆的元素個數之和是奇數或者是偶數,都得先「最大堆」 再「最小堆」 ,而當加入一個元素之后,元素個數為奇數的時候,再把最小堆的堆頂元素拿給最大堆就可以了。將元素放入優先隊列以后,優先隊列會自行調整(以對數時間復雜度),把最優值放入堆頂,是這道問題思路的關鍵

總結:

腦子里建立如下動態的過程:為了找到添加新數據以后,數據流的中位數,我們讓新數據在最大堆和最小堆中都走了一遍。而為了讓最大堆的元素多 1 個,我們讓從最小堆中又拿出堆頂元素「送回」給最大堆;將元素放入優先隊列以后,優先隊列會以對數時間復雜度自行調整,把「最優值」調整到堆頂,這是使用優先隊列解決這個問題的原因。如果不太熟悉優先隊列的朋友們,請復習一下優先隊列的相關知識,包括基本操作、理解上浮和下沉。這道題使用 Java 編碼看起來思路更清晰一些,在 Python 中的堆只有最小堆,在構造最大堆的時候,要繞一個彎子,具體請看如下參考代碼。

上述文字出自:https://leetcode-cn.com/problems/find-median-from-data-stream/solution/you-xian-dui-lie-python-dai-ma-java-dai-ma-by-liwe/

參考代碼:

class MedianFinder {int count;PriorityQueue<Integer> maxHeap;PriorityQueue<Integer> minHeap;/** initialize your data structure here. */public MedianFinder() {count = 0;maxHeap = new PriorityQueue<>((x, y) -> y - x);minHeap = new PriorityQueue<>();}public void addNum(int num) {count += 1;maxHeap.offer(num);minHeap.offer(maxHeap.poll());if(count%2!=0)maxHeap.offer(minHeap.poll());}public double findMedian() {if(count%2!=0)return (double)maxHeap.peek();elsereturn (double)(maxHeap.peek()+minHeap.peek())/2;} }/*** Your MedianFinder object will be instantiated and called as such:* MedianFinder obj = new MedianFinder();* obj.addNum(num);* double param_2 = obj.findMedian();*/

復雜度分析:

時間復雜度:O(logN),優先隊列的出隊入隊操作都是對數級別的,數據在兩個堆中間來回操作是常數級別的,綜上時間復雜度是 O(logN) 級別的;
空間復雜度:O(N),使用了三個輔助空間,其中兩個堆的空間復雜度是O(?2N),一個表示數據流元素個數的計數器 count,占用空間 O(1),綜上空間復雜度為 O(N)。

題目二:480. 滑動窗口中位數

問題描述

給你一個數組 nums,有一個長度為 k 的窗口從最左端滑動到最右端。窗口中有 k 個數,每次窗口向右移動 1 位。你的任務是找出每次窗口移動后得到的新窗口中元素的中位數,并輸出由它們組成的數組。

示例:

給出?nums = [1,3,-1,-3,5,3,6,7],以及?k = 3,返回該滑動窗口的中位數數組?[1,-1,-1,3,5,6]。

窗口位置 ? ? ? ? ? ? ? ? ? ? ?中位數

--------------- ? ? ? ? ? ? ? -----

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

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

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

?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] ? ? ?6

算法思路

本題考查動態維護數組的中位數。我們思考中位數的性質:如果一個數是中位數,那么在這個數組中,大于中位數的數目和小于中位數的數目,要么相等,要么就相差一。因此,我們采用對頂堆的做法,控制所有小于等于的數字放到一個堆中,控制所有比中位數大的數字放到另一個堆中,并且保證兩個堆的數目相差小于等于1。這樣就可以保證每一次查詢中位數的時候,答案一定出于兩個堆的堆頂元素之一。因此選定數據結構:優先隊列。因為優先隊列采用的是堆結構,正好符合我們的需求。我們將所有小于等于中位數的元素放到大頂堆,將所有大于中位數的元素放到小頂堆。

1)初始化方法如下:

  • 將前K個元素全部插入到大頂堆中。從大頂堆中彈出K/2個元素到小頂堆中。
  • 這樣,當K為奇數,則大頂堆元素比小頂堆元素多1;當K為偶數,兩個堆元素相等。

2)取中位數的操作:

  • 我們的插入操作可以保證每次優先插入到大頂堆中,因此大頂堆中的元素個數大于等于小頂堆的元素個數。
  • 當K為奇數時候,中位數是元素數量較多的大頂堆 堆頂元素。
  • 當K為偶數時候,中位數是大頂堆和小頂堆的堆頂元素平均值。

3)窗口滑動過程中的操作:

  • 假定在上一次滑動之后,已經有大頂堆和小頂堆元素數目相差小于等于1.
  • 設置當前的滑動時,balance = 0。balance表示大頂堆元素數目減去小頂堆元素個數。
  • 刪除窗口左側的元素:由于堆無法直接刪除掉某個指定元素,先欠下這個賬,等某次元素出現在堆頂的時候,再刪除他。mp記錄這個元素欠賬的個數。mp[left]++;雖然沒有真的在堆數據結構中刪除窗口最左側的元素,但是在我們的心中已經刪掉他了。堆兩側的平衡性發生了變化。如果left<=大頂堆.top(),就說明刪掉的元素在大頂堆中,我們讓balance--;否則,就說明刪掉的元素在小頂堆中,讓balance++;
  • 添加進來窗口右側的元素。如果right<=大頂堆.top(),就應該讓這個元素放到samll堆里面,balance++;否則放到小頂堆里,balance--。
  • 經過上面的操作,balance要么為0,要么為2,要么為-2。我們需要經過調整使得balance為0。
  • 如果balance為0,在這次窗口滑動之前已經是平衡的,這次調整也沒有讓兩堆的數目變化,所以不用調整兩邊的堆。
  • 如果balance為2,就說明small堆的元素比big堆的元素多了兩個。從small堆減少一個,big堆里增加一個,就可以讓兩邊相等。big.push(small.top());small.pop();
  • 如果balance為-2,就說明big堆的元素比small堆的元素多了兩個。從big堆減少一個,small堆里增加一個,就可以讓兩邊相等。small.push(big.top());big.pop();
  • 調整完了,現在該欠債還錢了。不能讓那些早該刪除的元素涉及到中位數的運算。
  • 分別檢查兩邊的堆頂元素,如果堆頂元素欠著債,則彈出堆頂元素,直到堆頂元素沒有欠債為止。有朋友問了:堆頂下面也有欠債的怎么辦呢?我們之前說過,取中位數的時候只與堆頂元素有關,至于那些堆頂下面欠著債的,欠著就欠著吧,等他們到堆頂的時候再彈出去就好了。
  • 最后,添加中位數即可。

上段文字出自:https://leetcode-cn.com/problems/sliding-window-median/solution/feng-xian-dui-chong-shuang-dui-dui-ding-hq1dt/

參考代碼:

class Solution {public double[] medianSlidingWindow(int[] nums, int k) {DualHeap dh = new DualHeap(k);for (int i = 0; i < k; ++i) {dh.insert(nums[i]);}double[] ans = new double[nums.length - k + 1];ans[0] = dh.getMedian();for (int i = k; i < nums.length; ++i) {dh.insert(nums[i]);dh.erase(nums[i - k]);ans[i - k + 1] = dh.getMedian();}return ans;} }class DualHeap {// 大根堆,維護較小的一半元素private PriorityQueue<Integer> small;// 小根堆,維護較大的一半元素private PriorityQueue<Integer> large;// 哈希表,記錄「延遲刪除」的元素,key 為元素,value 為需要刪除的次數private Map<Integer, Integer> delayed;private int k;// small 和 large 當前包含的元素個數,需要扣除被「延遲刪除」的元素private int smallSize, largeSize;public DualHeap(int k) {this.small = new PriorityQueue<Integer>(new Comparator<Integer>() {public int compare(Integer num1, Integer num2) {return num2.compareTo(num1);}});this.large = new PriorityQueue<Integer>(new Comparator<Integer>() {public int compare(Integer num1, Integer num2) {return num1.compareTo(num2);}});this.delayed = new HashMap<Integer, Integer>();this.k = k;this.smallSize = 0;this.largeSize = 0;}public double getMedian() {return (k & 1) == 1 ? small.peek() : ((double) small.peek() + large.peek()) / 2;}public void insert(int num) {if (small.isEmpty() || num <= small.peek()) {small.offer(num);++smallSize;} else {large.offer(num);++largeSize;}makeBalance();}public void erase(int num) {delayed.put(num, delayed.getOrDefault(num, 0) + 1);if (num <= small.peek()) {--smallSize;if (num == small.peek()) {prune(small);}} else {--largeSize;if (num == large.peek()) {prune(large);}}makeBalance();}// 不斷地彈出 heap 的堆頂元素,并且更新哈希表private void prune(PriorityQueue<Integer> heap) {while (!heap.isEmpty()) {int num = heap.peek();if (delayed.containsKey(num)) {delayed.put(num, delayed.get(num) - 1);if (delayed.get(num) == 0) {delayed.remove(num);}heap.poll();} else {break;}}}// 調整 small 和 large 中的元素個數,使得二者的元素個數滿足要求private void makeBalance() {if (smallSize > largeSize + 1) {// small 比 large 元素多 2 個large.offer(small.poll());--smallSize;++largeSize;// small 堆頂元素被移除,需要進行 pruneprune(small);} else if (smallSize < largeSize) {// large 比 small 元素多 1 個small.offer(large.poll());++smallSize;--largeSize;// large 堆頂元素被移除,需要進行 pruneprune(large);}} } 超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生

總結

以上是生活随笔為你收集整理的滑动窗口—中值问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 中日黄色片 | 亚洲一在线 | 日韩伦理大全 | 欧美色图在线播放 | 胖女人做爰全过程 | 免费看的av网站 | 蜜桃视频一区二区三区在线观看 | 欧美成人秋霞久久aa片 | 一级片在线免费看 | 女人裸体无遮挡 | 亚洲永久在线 | 男女午夜网站 | 91看片在线观看 | 姝姝窝人体www聚色窝 | 狠狠人妻久久久久久综合麻豆 | 日本欧美不卡 | 久久亚洲精品小早川怜子 | 日韩黄色在线视频 | av无码久久久久久不卡网站 | 九色.com| xvideos成人免费视频 | 亚洲色图丝袜美腿 | 99日精品| 成人激情四射网 | 用力抵着尿进去了h | 九一在线观看免费高清视频 | 国产精品白虎 | 精品一区二区不卡 | 五月婷婷激情网 | 成人高清网站 | 在线视频一区二区 | 午夜伦理福利视频 | 久久久久亚洲日日精品 | 91成人毛片 | 亚洲一区二区免费在线观看 | 一级特黄aa大片免费播放 | 亚洲一区二区三区在线观看视频 | 亚洲日本欧美 | 成人免费在线电影 | 日本中文不卡 | 天干夜夜爽爽日日日日 | 老司机免费精品视频 | 国产精品久久久国产盗摄 | 成年人视频在线观看免费 | 91嫩草视频在线观看 | 影视先锋av资源 | 色欧美亚洲 | 黄色精品 | 亚洲精品网站在线 | 亚洲熟女综合一区二区三区 | 日韩一区二区三区高清 | 黄色大片在线免费观看 | 久久人人人 | 亚洲 欧美 激情 另类 | 捆绑中国女人hd视频 | 日本大尺度吃奶做爰久久久绯色 | 国产精品6666 | 亚洲免费高清视频 | 丝袜国产一区 | 国产综合无码一区二区色蜜蜜 | 国产精品xxx视频 | 欧美资源在线观看 | 五月天综合视频 | 99精品欧美一区二区 | 国产麻豆一精品一av一免费 | 亚洲顶级毛片 | 中文字幕亚洲激情 | 97色在线视频 | 性做爰视频免费播放大全 | 欧美日韩午夜精品 | 五十路japanese55丰满 | 久热网| 在线观看污网站 | 日韩精品免费在线观看 | 色翁荡息又大又硬又粗又爽 | 都市豪门艳霸淫美妇 | av天天有| 久久av影院 | 亚洲黄色av | 国产精品厕所 | 国内成人免费视频 | 青青草成人影视 | 日韩极品少妇 | 狠狠干性视频 | 日韩av首页 | 亚洲欧美中文日韩在线观看 | 成人免费影视网站 | 日韩精品欧美 | 亚洲双插 | 亚洲精品第三页 | 久久精品国产亚洲av嫖农村妇女 | 中文字幕一区二区三区乱码在线 | 人人九九精 | 男女深夜福利 | 成年人黄色一级片 | 最色网站 | 天天舔天天摸 | 免费观看一区二区三区视频 | 国产精品国产三级国产普通话对白 |