|
| 1 | +// * Description : |
| 2 | +// Given an array of integers nums and the length of subarrays |
| 3 | +// print all medians of each subarrays |
| 4 | +// * Example : |
| 5 | +// Array : [5,2,2,7,3,7,9,0,2,3], Subarray length : 5 |
| 6 | +// Should print : 3 3 7 7 3 3 |
| 7 | +// The first subarray is [5, 2, 2, 7, 3], then the median is 3 |
| 8 | +// * Complexity : |
| 9 | +// O(N log K) time, O(N) space, N = array.size(), K = subarray.size() |
| 10 | + |
| 11 | +#include <iostream> |
| 12 | +#include <vector> |
| 13 | +#include <set> |
| 14 | + |
| 15 | +using namespace std; |
| 16 | + |
| 17 | +// Method : |
| 18 | +// Firstly initialize two heaps, lower and upper such that |
| 19 | +// abs(lower.size() - upper.size()) <= 1 && |
| 20 | +// median >= lower[i] && median <= upper[i] |
| 21 | +// The median is either the average of the two top values |
| 22 | +// or the top value of the greatest heap. |
| 23 | +// To add a value add it to the smallest heap and swap tops |
| 24 | +// if lower and upper don't follow the first condition. |
| 25 | +// To remove a value we find it, remove it and add the top of |
| 26 | +// the other heap to the updated heap (sizes are now the same). |
| 27 | +// We just remove and then add an item for each index of [0, N-k) |
| 28 | +// to simulate a sliding window. |
| 29 | +vector<double> medianSubarray(vector<int>& values, int k) { |
| 30 | + // We use long long instead of int to avoid overflows |
| 31 | + // median >= lower[i] && median <= upper[i] |
| 32 | + multiset<long long, greater<long long>> lower; |
| 33 | + multiset<long long> upper; |
| 34 | + vector<double> medians; |
| 35 | + |
| 36 | + // Initialize lower and upper |
| 37 | + for (int i = 0; i < k; ++i) { |
| 38 | + if (lower.size() <= upper.size()) |
| 39 | + lower.insert(values[i]); |
| 40 | + else |
| 41 | + upper.insert(values[i]); |
| 42 | + |
| 43 | + // Swap values if heaps aren't balanced |
| 44 | + if (!lower.empty() && !upper.empty() && |
| 45 | + *lower.begin() > *upper.begin()) { |
| 46 | + long long tmp = *lower.begin(); |
| 47 | + lower.erase(lower.begin()); |
| 48 | + lower.insert(*upper.begin()); |
| 49 | + upper.erase(upper.begin()); |
| 50 | + upper.insert(tmp); |
| 51 | + } |
| 52 | + } |
| 53 | + |
| 54 | +// To get the median inline |
| 55 | +#define GET_MEDIAN (lower.size() == upper.size() ? \ |
| 56 | + (*lower.begin() + (*upper.begin() - *lower.begin()) * .5) : \ |
| 57 | + lower.size() > upper.size() ? *lower.begin() : *upper.begin()) |
| 58 | + |
| 59 | + medians.push_back(GET_MEDIAN); |
| 60 | + |
| 61 | + for (int i = 0; i < values.size() - k; ++i) { |
| 62 | + // Remove the i item |
| 63 | + bool removed = false; |
| 64 | + if (!lower.empty() && values[i] <= *lower.begin()) { |
| 65 | + // Remove it |
| 66 | + auto target = lower.find(values[i]); |
| 67 | + if (target != lower.end()) { |
| 68 | + lower.erase(target); |
| 69 | + removed = true; |
| 70 | + |
| 71 | + // Insert the top of the other heap to the updated heap |
| 72 | + if (!upper.empty()) { |
| 73 | + lower.insert(*upper.begin()); |
| 74 | + upper.erase(upper.begin()); |
| 75 | + } |
| 76 | + } |
| 77 | + } |
| 78 | + |
| 79 | + if (!removed) { |
| 80 | + // Remove it |
| 81 | + upper.erase(upper.find(values[i])); |
| 82 | + |
| 83 | + // Insert the top of the other heap to the updated heap |
| 84 | + if (!lower.empty()) { |
| 85 | + upper.insert(*lower.begin()); |
| 86 | + lower.erase(lower.begin()); |
| 87 | + } |
| 88 | + } |
| 89 | + |
| 90 | + // Add the i + k item |
| 91 | + if (lower.size() <= upper.size()) |
| 92 | + lower.insert(values[i + k]); |
| 93 | + else |
| 94 | + upper.insert(values[i + k]); |
| 95 | + |
| 96 | + // Swap values if heaps aren't balanced |
| 97 | + if (!lower.empty() && !upper.empty() && |
| 98 | + *lower.begin() > *upper.begin()) { |
| 99 | + long long tmp = *lower.begin(); |
| 100 | + lower.erase(lower.begin()); |
| 101 | + lower.insert(*upper.begin()); |
| 102 | + upper.erase(upper.begin()); |
| 103 | + upper.insert(tmp); |
| 104 | + } |
| 105 | + |
| 106 | + medians.push_back(GET_MEDIAN); |
| 107 | + } |
| 108 | + |
| 109 | + return medians; |
| 110 | +} |
| 111 | + |
| 112 | +int main() { |
| 113 | + vector<pair<int, vector<int>>> dataset = { |
| 114 | + {5, {5,2,2,7,3,7,9,0,2,3}}, |
| 115 | + {3, {1,3,-1,-3,5,3,6,7}}, |
| 116 | + {1, {1,2}}, |
| 117 | + {2, {2147483647,2147483647}}, |
| 118 | + }; |
| 119 | + |
| 120 | + // Should be : |
| 121 | + // 3 3 7 7 3 3 |
| 122 | + // 1 -1 -1 3 5 6 |
| 123 | + // 1 2 |
| 124 | + // 2.14748e+09 |
| 125 | + for (auto test : dataset) { |
| 126 | + auto y = medianSubarray(test.second, test.first); |
| 127 | + for (double median : y) |
| 128 | + cout << median << " "; |
| 129 | + |
| 130 | + cout << endl; |
| 131 | + } |
| 132 | + |
| 133 | + return 0; |
| 134 | +} |
0 commit comments