LeetCode 632. Smallest Range Covering Elements from K Lists
原题链接
困难
作者:
JasonSun
,
2020-02-12 05:58:39
,
所有人可见
,
阅读 697
Algorithm (Sliding Window)
- Denote the input intervals by $\{I_{i}\}_{i=1}^{n}.$ We first merge elements along with its interval id in all intervals into one big array, which we will denote as $M.$ Then we sort $M$ by the interval element (not interval id).
- Suppose the optimal solution to be $I_{\mathrm{OPT}}.$ Then we note that $I_{\mathrm{OPT}}$ actually corresponds to a continuous segment $S$ in $M$ and the set $(\bigcup_{i=1}^{N}I_{\mathrm{OPT}}\cap I_{i})$ corresponds to elements in $S$ (it’s possible that it does not cover all of $S$).
- So this problem is reduced to finding the smallest segment in $S$ that contains elements from all intervals. And this could be solved in $O(n)$ time using a sliding window approach with the help of a counter map which keeps track of the interval id that were included.
Code (Cpp17)
class Solution {
public:
vector<int> smallestRange(vector<vector<int>>& nums) {
const int k = size(nums);
const auto merged_nums = [&](std::vector<std::array<int, 2>> self = {}) {
for (int i = 0; i < size(nums); ++i)
for (const auto x : nums[i])
self.emplace_back(std::array<int, 2>{x, i});
std::sort(begin(self), end(self), [&](const auto& x, const auto& y) {
return x[0] < y[0];
});
return self;
}();
struct interval_t {
int left;
int right;
};
auto comp = [&](const interval_t& a, const interval_t& b) {
if (std::abs(a.left - a.right) == std::abs(b.left - b.right))
return a.left < b.left;
else
return std::abs(a.left - a.right) < std::abs(b.left - b.right);
};
const auto solution = [&](interval_t acc = {0, INT_MAX / 2}) {
const struct state_t {
mutable std::deque<std::array<int, 2>> window;
mutable std::unordered_map<int, int> counter;
} state;
auto pop = [&] {
auto& [window, counter] = state;
if (--counter[window.front()[1]] <= 0)
counter.erase(window.front()[1]);
window.pop_front();
};
auto emplace_back = [&](const std::array<int, 2>& x) {
auto& [window, counter] = state;
window.emplace_back(x);
counter[x[1]]++;
while (counter.size() == k) {
acc = std::min(acc, interval_t{window.front()[0], window.back()[0]}, comp);
pop();
}
};
for (const auto x : merged_nums) emplace_back(x);
return acc;
}();
return {solution.left, solution.right};
}
};