堆應用例題三連

一個數據流中,隨時可以取得中位數。


題目描述:有一個源源不斷地吐出整數的數據流,假設你有足夠的空間來保存吐出的數。請設計一個名叫MedianHolder的結構,MedianHolder可以隨時取得之前吐出所有樹的中位數。

要求:

1.如果MedianHolder已經保存了吐出的N個數,那么任意時刻將一個新的數加入到MedianHolder的過程中,時間復雜度O(logN)。

2.取得已經吐出的N個數整體的中位數的過程,時間復雜度O(1).

?

看這要求就應該感覺到和堆相關吧?

但是進一步沒那么好想。

設計的MedianHolder中有兩個堆,一個是大根堆,一個是小根堆。大根堆中含有接收的所有數中較小的一半,并且按大根堆的方式組織起來,那么這個堆的堆頂就是較小一半的數中最大的那個。小根堆中含有接收的所有數中較大的一半,并且按小根堆的方式組織起來,那么這個堆的堆頂就是較大一半的數中最小的那個。

例如,如果已經吐出的數為6,1,3,0,9,8,7,2.

較小的一半為:0,1,2,3,那么3就是這一半的數組成的大根堆的堆頂

較大的一半為:6,7,8,9,那么6就是這一半的數組成的小根堆的堆頂

因為此時數的總個數為偶數,所以中位數就是兩個堆頂相加,再除以2.

如果此時新加入一個數10,那么這個數應該放進較大的一半里,所以此時較大的一半數為6,7,8,9,10,此時6依然是這一半的數組成的小根堆的堆頂,因為此時數的總個數為奇數,所以中位數應該是正好處在中間位置的數,而此時大根堆有4個數,小根堆有5個數,那么小根堆的堆頂6就是此時的中位數。

如果此時又新加入一個數11,那么這個數也應該放進較大的一半里,此時較大一半的數為:6,7,8,9,10,11.這個小根堆大小為6,而大根堆的大小為4,所以要進行如下調整:

1.如果大根堆的size比小根堆的size大2,那么從大根堆里將堆頂元素彈出,并放入小根堆里

2,如果小根堆的size比大根堆的size大2,那么從小根堆里將堆頂彈出,并放入大根堆里。

經過這樣的調整之后,大根堆和小根堆的size相同。

總結如下:

大根堆每時每刻都是較小的一半的數,堆頂為這一堆數的最大值
小根堆每時每刻都是較大的一半的數,堆頂為這一堆數的最小值
新加入的數根據與兩個堆堆頂的大小關系,選擇放進大根堆或者小根堆里(或者放進任意一個堆里)
當任何一個堆的size比另一個size大2時,進行如上調整的過程。


這樣隨時都可以知道已經吐出的所有數處于中間位置的兩個數是什么,取得中位數的操作時間復雜度為O(1),同時根據堆的性質,向堆中加一個新的數,并且調整堆的代價為O(logN)。
?

import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;/*** 隨時找到數據流的中位數* 思路:* 利用一個大根堆和一個小根堆去保存數據,保證前一半的數放在大根堆,后一半的數放在小根堆* 在添加數據的時候,不斷地調整兩個堆的大小,使得兩個堆保持平衡* 要取得的中位數就是兩個堆堆頂的元素*/
public class MedianQuick {public static class MedianHolder {private PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(new MaxHeapComparator());private PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>(new MinHeapComparator());/*** 調整堆的大小* 當兩個堆的大小差值變大時,從數據多的堆中彈出一個數據進入另一個堆中*/private void modifyTwoHeapsSize() {if (this.maxHeap.size() == this.minHeap.size() + 2) {this.minHeap.add(this.maxHeap.poll());}if (this.minHeap.size() == this.maxHeap.size() + 2) {this.maxHeap.add(this.minHeap.poll());}}/*** 添加數據的過程** @param num*/public void addNumber(int num) {if (this.maxHeap.isEmpty()) {this.maxHeap.add(num);return;}if (this.maxHeap.peek() >= num) {this.maxHeap.add(num);} else {if (this.minHeap.isEmpty()) {this.minHeap.add(num);return;}if (this.minHeap.peek() > num) {this.maxHeap.add(num);} else {this.minHeap.add(num);}}modifyTwoHeapsSize();}/*** 獲取中位數** @return*/public Integer getMedian() {int maxHeapSize = this.maxHeap.size();int minHeapSize = this.minHeap.size();if (maxHeapSize + minHeapSize == 0) {return null;}Integer maxHeapHead = this.maxHeap.peek();Integer minHeapHead = this.minHeap.peek();if (((maxHeapSize + minHeapSize) & 1) == 0) {return (maxHeapHead + minHeapHead) / 2;}return maxHeapSize > minHeapSize ? maxHeapHead : minHeapHead;}}/*** 大根堆比較器*/public static class MaxHeapComparator implements Comparator<Integer> {@Overridepublic int compare(Integer o1, Integer o2) {if (o2 > o1) {return 1;} else {return -1;}}}/*** 小根堆比較器*/public static class MinHeapComparator implements Comparator<Integer> {@Overridepublic int compare(Integer o1, Integer o2) {if (o2 < o1) {return 1;} else {return -1;}}}// for testpublic static int[] getRandomArray(int maxLen, int maxValue) {int[] res = new int[(int) (Math.random() * maxLen) + 1];for (int i = 0; i != res.length; i++) {res[i] = (int) (Math.random() * maxValue);}return res;}// for test, this method is ineffective but absolutely rightpublic static int getMedianOfArray(int[] arr) {int[] newArr = Arrays.copyOf(arr, arr.length);Arrays.sort(newArr);int mid = (newArr.length - 1) / 2;if ((newArr.length & 1) == 0) {return (newArr[mid] + newArr[mid + 1]) / 2;} else {return newArr[mid];}}public static void printArray(int[] arr) {for (int i = 0; i != arr.length; i++) {System.out.print(arr[i] + " ");}System.out.println();}public static void main(String[] args) {boolean err = false;int testTimes = 200000;for (int i = 0; i != testTimes; i++) {int len = 30;int maxValue = 1000;int[] arr = getRandomArray(len, maxValue);MedianHolder medianHold = new MedianHolder();for (int j = 0; j != arr.length; j++) {medianHold.addNumber(arr[j]);}if (medianHold.getMedian() != getMedianOfArray(arr)) {err = true;printArray(arr);break;}}System.out.println(err ? "Oops..what a fuck!" : "today is a beautiful day^_^");}
}

金條

?

一塊金條切成兩半,是需要花費和長度數值一樣的銅板的。比如長度為20的金條,不管切成長度多大的兩半,都要花費20個銅板。一群人想整分整塊金條,怎么分最省銅板?
例如,給定數組{10,20,30},代表一共三個人,整塊金條長度為10+20+30=60,金條要分成10,20,30三個部分。如果,先把長度60的金條分成10和50,花費60,再把長度為50的金條分成20和30,花費50,一共花費110個銅板。

但是如果,先把長度60的金條分成30和30,花費60,再把長度30金條分成10和30,花費30,一共花費90個銅板。

輸入一個數組,返回分割的最小代價。

首先我們要明白一點:不管合并策略是什么我們一共會合并n-1次,這個次數是不會變的。

我們要做的就是每一次都做最優選擇。

合為最優?

最小的兩個數合并就是最優。

所以

1)首先構造小根堆

2)每次取最小的兩個數(小根堆),使其代價最小。并將其和加入到小根堆中

3)重復(2)過程,直到最后堆中只剩下一個節點。

?

花費為每次花費的累加。

代碼略。

?

項目最大收益(貪心問題)


輸入:參數1,正數數組costs,參數2,正數數組profits,參數3,正數k,參數4,正數m

costs[i]表示i號項目的花費profits[i]表示i號項目在扣除花費之后還能掙到的錢(利潤),k表示你不能并行,只能串行的最多做k個項目,m表示你初始的資金。

說明:你每做完一個項目,馬上獲得的收益,可以支持你去做下一個項目。

輸出:你最后獲得的最大錢數。

思考:給定一個初始化投資資金,給定N個項目,想要獲得其中最大的收益,并且一次只能做一個項目。這是一個貪心策略的問題,應該在能做的項目中選擇收益最大的。

按照花費的多少放到一個小根堆里面,然后要是小根堆里面的頭節點的花費少于給定資金,就將頭節點一個個取出來,放到按照收益的大根堆里面。然后做大根堆頂的項目即可。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/445527.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/445527.shtml
英文地址,請注明出處:http://en.pswp.cn/news/445527.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

HistCite 的使用方法

摘要 讀文獻自然要讀精品&#xff0c;在面對一個陌生領域&#xff0c;如何才能以最快速度定位精品文獻呢&#xff1f;本文將詳細介紹 HistCite 的使用方法&#xff0c;結合 Web of Science 和 Endnote &#xff0c;演示如何在幾個小時之內&#xff0c;對某個陌生領域的文獻進行…

數組基操三連(2)

轉圈打印矩陣 題目&#xff1a; 給定一個整型矩陣matrix&#xff0c;請按照轉圈的方式打印它。例如&#xff1a;1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,打印結果為&#xff1a;1,2,3,4,5,12,16,15,14,13,9,5,6,7,11,10 要求&#xff1a; 額外空間復雜度為O&#xff08;1&a…

數據結構課上筆記7

介紹棧和隊列基本概念和用法。 設輸入序列1、2、3、4&#xff0c;則下述序列中&#xff08; &#xff09;不可能是出棧序列。【中科院中國科技大學2005】 A. 1、2、3、4 B. 4、 3、2、1 C. 1、3、4、2 D.&#xff14;、1、2、3 選…

ROC曲線與AUC值

ROC曲線與AUC值 1.概述AUC&#xff08;Area Under roc Curve&#xff09;是一種用來度量分類模型好壞的一個標準。這樣的標準其實有很多&#xff0c;例如&#xff1a;大約10年前在machine learning文獻中一統天下的標準&#xff1a;分類精度&#xff1b;在信息檢索(IR)領域中常…

設置SSH免密碼自動登錄(使用別名)

每次登錄服務器都要寫一大串的用戶名&#xff08;username服務器地址&#xff09;和登錄密碼十分的繁瑣&#xff0c;所以本文就告訴大家如何通過修改配置文件&#xff0c;達到只需要輸入&#xff1a;ssh jack(你起的別名)就可以一鍵登錄到服務器中。 1.創建公鑰&#xff08;相當…

串的定長表示

思想和代碼都不難&#xff0c;和線性表也差不多&#xff0c;串本來就是數據受限的線性表。 串連接&#xff1a; #include <stdio.h> #include <string.h> //串的定長順序存儲表示 #define MAXSTRLEN 255 //用戶可在255以內定義最大串長 typedef unsigned cha…

周志華《Machine Learning》 學習筆記系列(1)--緒論

機器學習致力于研究如何通過計算手段&#xff0c;利用經驗來改善系統本身的性能&#xff0c;在計算機系統中&#xff0c;“經驗”通常是以“數據”形式存在的&#xff0c;所以&#xff0c;機器學習的主要內容是關于在計算機上從數據中產生“模型”的算法&#xff0c;即學習算法…

輕松理解牛頓迭代法且用其求平方根

牛頓迭代法概述 牛頓迭代法&#xff08;Newton’s method&#xff09;又稱為牛頓-拉弗森方法&#xff08;Newton-Raphson method&#xff09;&#xff0c;它是牛頓在17世紀提出的一種在實數域和復數域上近似求解方程的方法。 牛頓迭代公式 設rrr是f(x)0f(x)0f(x)0的根&#…

map+DP leetcode446

如果數字序列由至少三個元素組成并且任何兩個連續元素之間的差異相同&#xff0c;則稱為算術序列。 例如&#xff0c;這些是算術序列&#xff1a; 1&#xff0c;3&#xff0c;5&#xff0c;7&#xff0c;9 7&#xff0c;7,7&#xff0c;7 3&#xff0c;-1&#xff0c;-5&am…

如何使用cookie信息,完成自動登錄

在做爬蟲任務的時候&#xff0c;我們常常會遇到很多網頁必須登錄后&#xff0c;才可以開放某些頁面。所以登錄是爬取網頁的第一步。但是&#xff0c;通過post表單&#xff08;包含用戶名和密碼&#xff09;的方法&#xff0c;對于那些不需要輸入比較復雜的驗證碼的網頁&#xf…

Spring Cloud 學習筆記(1 / 3)

Spring Cloud 學習筆記&#xff08;2 / 3&#xff09; Spring Cloud 學習筆記&#xff08;3 / 3&#xff09; ---01_前言閑聊和課程說明02_零基礎微服務架構理論入門03_第二季Boot和Cloud版本選型04_Cloud組件停更說明05_父工程Project空間新建06_父工程pom文件07_復習Depend…

后綴樹/后綴數組

字典樹&#xff1a;https://blog.csdn.net/hebtu666/article/details/83141560 后綴樹&#xff1a;后綴樹&#xff0c;就是把一串字符的所有后綴保存并且壓縮的字典樹。 相對于字典樹來說&#xff0c;后綴樹并不是針對大量字符串的&#xff0c;而是針對一個或幾個字符串來解決…

kaggle(02)-房價預測案例(基礎版)

房價預測案例 Step 1: 檢視源數據集 import numpy as np import pandas as pd讀入數據 一般來說源數據的index那一欄沒什么用&#xff0c;我們可以用來作為我們pandas dataframe的index。這樣之后要是檢索起來也省事兒。 有人的地方就有鄙視鏈。跟知乎一樣。Kaggle的也是個處…

為什么Python中整型不會溢出

前言 本次分析基于 CPython 解釋器&#xff0c;python3.x版本 在python2時代&#xff0c;整型有 int 類型和 long 長整型&#xff0c;長整型不存在溢出問題&#xff0c;即可以存放任意大小的整數。在python3后&#xff0c;統一使用了長整型。這也是吸引科研人員的一部分了&am…

如何使用github中的pull request功能?

* pull request是社會化編程的象征&#xff0c;通過這個功能&#xff0c;你可以參與到別人開發的項目中&#xff0c;并做出自己的貢獻。pull request是自己修改源代碼后&#xff0c;請求對方倉庫采納的一種行為*–《github入門與實踐》 下面具體說一下github中使用pull reque…

「假裝努力」

有多少人在「假裝努力」&#xff1f; 又有多少人在「真正成長」&#xff1f; 再努力努力 回想起當年畢業后&#xff0c;在北京和室友合租的日子。 那時&#xff0c;我在工作&#xff0c;室友在培訓。 一天&#xff0c;我下班回來&#xff0c;聽見他在電話里和家人爭吵&…

如何閱讀論文?

本文主要講述了如何才能高效的閱讀一篇論文&#xff01;&#xff01;

貪吃蛇js

python都學不懂&#xff0c;c又不會&#xff0c;只能寫寫js來維持生活了。555555 js&#xff1a; window.onload function() {var wrap document.getElementsByClassName("wrap")[0];var uls document.getElementsByClassName("sbody")[0];var hand …

Android studio安裝過程中入的坑的記錄與記錄

Android studio安裝過程中入的坑的記錄與記錄 * 由于最近項目的需求&#xff0c;所以最近一直在配置安卓的開發環境&#xff0c;之前用的是Eclipse ADT的模式開發的&#xff0c;配置環境也花了一些時間&#xff0c;但是由于谷歌大力扶持它的親兒子Android Studio&#xff0c;…

動態規劃基礎水題提綱

提綱 漢諾塔 漢諾塔&#xff1a;漢諾塔&#xff08;又稱河內塔&#xff09;問題是源于印度一個古老傳說的益智玩具。大梵天創造世界的時候做了三根金剛石柱子&#xff0c;在一根柱子上從下往上按照大小順序摞著64片黃金圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序重新…