We use cookies to ensure you have the best browsing experience on our website. Please read our cookie policy for more information about how we use cookies.
- Heaps: Find the Running Median
- Discussions
Heaps: Find the Running Median
Heaps: Find the Running Median
+ 0 comments Ruby solution with custom Binary Heap implementation (as there is no built-in Heap in Ruby's core lib)
class AbstractBinHeap def initialize @store = [] end def empty? @store.empty? end def size @store.size end alias length size def to_s tmp = dup order = [] order << tmp.pop until tmp.empty? order.join(' ') end alias inspect to_s def add(e) @store << e heapify_up(@store.size - 1) end alias << add def peek if empty? nil else @store[0] end end alias next peek def pop return nil if empty? e = @store[0] @store[0] = @store[-1] @store.pop heapify_down(0) e end # Delete first occurence of e. def delete(e) pos = @store.index(e) if pos.nil? nil else delete_at(pos) end end protected attr_writer :store def dup cl = self.class.new cl.store = @store.dup cl end private def delete_at(pos) return nil if pos >= @store.length e = @store[pos] @store[pos] = most_sig_val heapify_up(pos) pop e end def parent(pos) (pos - 1) / 2 end def lchild(pos) pos * 2 + 1 end def rchild(pos) pos * 2 + 2 end def heapify_up(pos) return if pos == 0 || pos >= @store.length loop do parent = (pos - 1) / 2 break unless pos > 0 && compare(@store[pos], @store[parent]) @store[pos], @store[parent] = @store[parent], @store[pos] pos = parent end end def heapify_down(pos) return if pos >= @store.length while lchild(pos) < @store.length lchild = lchild(pos) rchild = rchild(pos) minchild = if rchild < @store.length compare(@store[lchild], @store[rchild]) ? lchild : rchild else lchild end if compare(@store[minchild], @store[pos]) @store[pos], @store[minchild] = @store[minchild], @store[pos] pos = minchild else break end end end end class MinHeap < AbstractBinHeap private def compare(obj1, obj2) obj1 < obj2 end def most_sig_val -1 * Float::INFINITY end end class MaxHeap < AbstractBinHeap private def compare(obj1, obj2) obj1 > obj2 end def most_sig_val Float::INFINITY end end def running_median(arr) smaller = MaxHeap.new larger = MinHeap.new arr.map do |e| if smaller.empty? || e <= smaller.peek smaller << e else larger << e end if smaller.size < larger.size smaller << larger.pop elsif smaller.size - 1 > larger.size larger << smaller.pop end if larger.empty? smaller.peek else smaller.size == larger.size ? (smaller.peek + larger.peek) / 2 : smaller.peek end end end n = gets.to_i arr = Array.new(n) n.times { |i| arr[i] = gets.to_f } puts(running_median(arr).map { |m| format('%.1f', m) })
+ 0 comments Solution with my original Heap class and an optimized way faster one:
class Heap { // My original implementation - cagils constructor(comp) { this.heap = []; if (comp === "max" || !comp) this.comp = (a, b) => a > b; else if (comp === "min") this.comp = (a, b) => a < b; else this.comp = comp; } _heapify() { for (let i = parseInt(this.heap.length / 2 - 1); i >= 0; i--) Heap.heapify(this.heap, this.heap.length, i, this.comp); } static heapify(arr, n, i, comp) { let first = i; let li = 2*i+1; let ri = 2*i+2; if (li < n && comp(arr[li], arr[first])) first = li; if (ri < n && comp(arr[ri], arr[first])) first = ri; if (first !== i) { [arr[i], arr[first]] = [arr[first], arr[i]]; Heap.heapify(arr, n, first, comp); } } push = (data) => { this.heap.push(data); this._heapify(); }; remove(data) { const size = this.heap.length; let i = this.heap.findIndex((e) => e === data); if (i === -1) i = size; [this.heap[i], this.heap[size - 1]] = [this.heap[size - 1], this.heap[i]]; this.heap.splice(size - 1); this._heapify(); return data; } peek = () => this.heap[0]; pop = () => this.remove(this.heap[0]); size = () => this.heap.length; getList = () => this.heap; } class _Heap { // faster implementation constructor(comp) { this.a = []; if (comp === "min" || !comp) this.comp = (a, b) => a < b; else if (comp === "max") this.comp = (a, b) => a > b; else this.comp = comp; } up (i) { //const pi = (i - 1) >> 1;//Math.floor((i - 1) / 2) const pi = Math.floor((i - 1) / 2); if(this.comp(this.a[i], this.a[pi])) { [this.a[pi], this.a[i]] = [this.a[i], this.a[pi]]; this.up(pi); } } down (i) { const lci = i * 2 + 1; const rci = lci + 1; const pi = i; const a_i = this.a[i]; if(this.comp(this.a[lci], a_i) || this.comp(this.a[rci], a_i)) { if(this.comp(this.a[lci], a_i) && this.comp(this.a[rci], a_i)) i = this.comp(this.a[lci], this.a[rci]) ? lci : rci; else i = this.comp(this.a[lci], a_i) ? lci : rci; this.a[pi] = this.a[i]; this.a[i] = a_i; this.down(i); } } push(num) { this.a.push(num); this.up(this.a.length - 1); } pop() { const deletedVal = this.a[0]; this.a.length > 1 ? this.a[0] = this.a.pop() : this.a.pop(); this.down(0); return deletedVal; } peek() { return this.a[0] } size = () => this.a.length; getList = () => this.a; } function runningMedian(a) { const highers = new _Heap('min'); const lowers = new _Heap('max'); for (const n of a) { if (lowers.size() === 0 || lowers.peek() > n) lowers.push(n); else highers.push(n); let [big, small] = highers.size() > lowers.size() ? [highers, lowers] : [lowers, highers]; let diff = big.size() - small.size(); if (big.size() - small.size() > 1) { small.push(big.pop()); diff = 0; } const out = diff === 0 ? (big.peek() + small.peek()) / 2 : big.peek(); console.log(out.toFixed(1)) } }
+ 0 comments C++ Heaps Approach
void runningMedian(vector<int> arr) { priority_queue<int, vector<int>> mxheap; priority_queue<int, vector<int>, greater<int>> minheap; float med = arr[0]; mxheap.push(arr[0]); cout << fixed << setprecision(1) << med << endl; for (int i = 1; i < arr.size(); i++) { if (mxheap.size() == minheap.size()) { // if (mxheap.size() == 0) // { // mxheap.push(arr[i]); // med = mxheap.top(); // cout << med << endl; // return; // } if (arr[i] < mxheap.top()) { mxheap.push(arr[i]); med = (double)mxheap.top(); } else { minheap.push(arr[i]); med = (double)minheap.top(); } } else { if (mxheap.size() > minheap.size()) { if (arr[i] >= mxheap.top()) { minheap.push(arr[i]); } else { int temp = mxheap.top(); mxheap.pop(); mxheap.push(arr[i]); minheap.push(temp); } med = (mxheap.top() + minheap.top()) / 2.0; } else { if (arr[i] <= minheap.top()) { mxheap.push(arr[i]); } else { int temp = minheap.top(); minheap.pop(); minheap.push(arr[i]); mxheap.push(temp); } med = (mxheap.top() + minheap.top()) / 2.0; } } printf("%.1f \n",med); } }
+ 0 comments This works fine, but as I understand time complexity if O(n^2) due to add operation
List<Integer> aList = new ArrayList(n); Collections.fill(aList, Integer.MAX_VALUE); int lastIndex = -1; for (int i = 0; i < n; i++) { int aItem = scanner.nextInt(); scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?"); int index = Collections.binarySearch(aList, aItem); if (index < 0) { index = Math.abs(index) - 1; } aList.add(index, aItem); lastIndex++; if ((lastIndex + 1) % 2 == 0) { int item1 = aList.get((lastIndex + 1) / 2); int item2 = aList.get(((lastIndex + 1) / 2) - 1); System.out.println((item1 + item2) / 2.0); } else { System.out.println(aList.get((lastIndex + 1) / 2) / 1.0); } }
+ 0 comments Getting timeout and one wrong answer with this: Any suggestions?
#include <bits/stdc++.h> using namespace std; void maxHeapify(vector<int> &arr, int iBegin) { int iLeft = 2 * iBegin + 1; int iRight = iLeft + 1; int iLargest = iBegin; if (iLeft < arr.size() && arr[iLeft] > arr[iLargest]) iLargest = iLeft; if (iRight < arr.size() && arr[iRight] > arr[iLargest]) iLargest = iRight; if (iLargest != iBegin) { swap(arr[iLargest], arr[iBegin]); maxHeapify(arr, iLargest); } } void minHeapify(vector<int>& arr, int iBegin) { int iLeft = 2 * iBegin + 1; int iRight = iLeft + 1; int iSmallest = iBegin; if (iLeft < arr.size() && arr[iLeft] < arr[iSmallest]) iSmallest = iLeft; if (iRight < arr.size() && arr[iRight] < arr[iSmallest]) iSmallest = iRight; if (iSmallest != iBegin) { swap(arr[iSmallest], arr[iBegin]); minHeapify(arr, iSmallest); } } void buildMinHeap(vector<int>& arr) { for (int i = arr.size() / 2 - 1; i >= 0; i--) minHeapify(arr, i); } void buildMaxHeap(vector<int>& arr) { for (int i = arr.size() / 2 - 1; i >= 0; i--) maxHeapify(arr, i); } void findRunningMedian(vector<int> arr) { //median even = (maxHeap[0] + minHeap[0] ) / 2 //median odd = maxHeap[0] int i = 0; vector<int> minHeap; vector<int> maxHeap; minHeap.reserve(arr.size() / 2); maxHeap.reserve(arr.size() / 2); cout << fixed; cout << setprecision(1); while (i < arr.size()) { double median = 0.0; // add odd element to maxHeap, to keep it always >= minHeap if (i % 2 == 0) { // add to minHeap if greater than its min element if (minHeap.size() && minHeap[0] < arr[i]) { //add to minHeap minHeap.push_back(arr[i]); // move the min element to maxHeap to maintain size maxHeap.push_back(minHeap[0]); minHeap.erase(minHeap.begin()); buildMaxHeap(maxHeap); buildMinHeap(minHeap); } else { maxHeap.push_back(arr[i]); buildMaxHeap(maxHeap); } median = maxHeap[0]; } else { // add to maxHeap if less than minHeap[0] if (minHeap.size() && minHeap[0] > arr[i]) { //add to minHeap maxHeap.push_back(arr[i]); // move the max element to minHeap, to maintain size minHeap.push_back(maxHeap[0]); maxHeap.erase(maxHeap.begin()); buildMaxHeap(maxHeap); buildMinHeap(minHeap); } else { minHeap.push_back(arr[i]); // special case to handle 2 element array if (i == 1 && minHeap[0] < maxHeap[0]) { swap(minHeap[0], maxHeap[0]); } buildMinHeap(minHeap); } median = ((double)maxHeap[0] + (double)minHeap[0]) / 2; } cout << median << endl; i++; } } int main() { int n; cin >> n; cin.ignore(numeric_limits<streamsize>::max(), '\n'); vector<int> a(n); for (int i = 0; i < n; i++) { int a_item; cin >> a_item; cin.ignore(numeric_limits<streamsize>::max(), '\n'); a[i] = a_item; } findRunningMedian(a); return 0; }
Load more conversations
Sort 278 Discussions, By:
Please Login in order to post a comment