牛客17799题:滑动窗口+优先队列解决多数组最小区间
一、题目解读
牛客17799题要求在一个由K个有序数组组成的集合中,找到包含所有数组元素的最小区间范围。即需确定一个区间[range_start, range_end],使得每个数组中至少有一个元素落在该区间内,且区间长度最小。题目考验对多数组合并与区间优化的处理能力。
二、解题思路
1. 初始化:将每个数组的首元素加入小根堆(优先队列),记录当前堆顶元素(最小值)与最大值。
2. 滑动窗口:每次取出堆顶元素(当前窗口最小值),更新区间范围。若该元素所在数组存在后续元素,则将其加入堆并更新最大值。
3. 循环终止条件:当某个数组的所有元素已被遍历时结束,确保每个数组至少贡献一个元素到区间。
4. 区间更新逻辑:通过比较新旧区间的长度和起始值,动态维护最小范围。
三、解题步骤
1. 创建包含元素值、行索引、列索引的结构体,重载运算符支持优先队列排序。
2. 初始化堆:遍历K个数组首元素,加入堆并记录当前最大值。
3. 循环:
○ 弹出堆顶元素,更新区间范围(根据差值或起始值优先级)。
○ 若该元素非所在数组末尾,则将其下一元素加入堆并更新最大值。
○ 若某数组遍历完毕,终止循环。
4. 返回最终区间[range_start, range_end]。
四、代码与注释
#include <iostream> #include <vector> #include <queue> #include <climits> using namespace std; struct Element { int val; // 元素值 int row; // 所属数组索引 int col; // 在数组中的位置 bool operator>(const Element& other) const { return val > other.val; } }; vector<int> smallestRange(vector<vector<int>>& nums) { int k = nums.size(); priority_queue<Element, vector<Element>, greater<Element>> min_heap; int current_max = INT_MIN; // 初始化堆,放入每个数组的第一个元素 for (int i = 0; i < k; ++i) { min_heap.push({nums[i][0], i, 0}); current_max = max(current_max, nums[i][0]); } int range_start = 0, range_end = INT_MAX; while (true) { Element min_element = min_heap.top(); min_heap.pop(); // 更新最小区间 if (current_max - min_element.val < range_end - range_start) { range_start = min_element.val; range_end = current_max; } else if (current_max - min_element.val == range_end - range_start && min_element.val < range_start) { range_start = min_element.val; range_end = current_max; } // 如果某个数组已经遍历完,结束循环 if (min_element.col + 1 == nums[min_element.row].size()) { break; } // 将当前数组的下一个元素加入堆 int next_val = nums[min_element.row][min_element.col + 1]; min_heap.push({next_val, min_element.row, min_element.col + 1}); current_max = max(current_max, next_val); } return {range_start, range_end}; } int main() { int k, n; cin >> k >> n; vector<vector<int>> nums(k, vector<int>(n)); for (int i = 0; i < k; ++i) { for (int j = 0; j < n; ++j) { cin >> nums[i][j]; } } vector<int> result = smallestRange(nums); cout << result[0] << " " << result[1] << endl; return 0; }
五、总结
本解法核心在于利用优先队列维护多数组元素的有序性,通过滑动窗口动态调整区间范围,避免了暴力遍历所有组合。时间复杂度为O(NlogK)(N为总元素数,K为数组数量),空间复杂度为O(K)。通过优化区间更新逻辑,确保在相等长度时优先选择更小区间,从而准确求解最小范围。
原创内容 转载请注明出处